`
cloudtech
  • 浏览: 4604945 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

使用kbuild构建bzImage内核映像

 
阅读更多
这里通过以下三个最经典的步骤来分析下,一个bzImage内核映像是如何配置编译,并最终安装使用的。当然在整个内核构建过程中,还支持许多的特性,相信这个经典过程明确之后,分析其他的情况就不会太难了,这里以x86体系来做分析。分析版本2.6.34.1

(1) make menuconfig
研究代码最好的方法就是手眼并用,看代码的同时多多动手调试,我们先贴出了它实际运行的过程:
[root@www linux-2.6.34.1]# make menuconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
  HOSTCC  scripts/basic/hash
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/kxgettext.o
  HOSTCC  scripts/kconfig/lxdialog/checklist.o
  HOSTCC  scripts/kconfig/lxdialog/inputbox.o
  HOSTCC  scripts/kconfig/lxdialog/menubox.o
  HOSTCC  scripts/kconfig/lxdialog/textbox.o
  HOSTCC  scripts/kconfig/lxdialog/util.o
  HOSTCC  scripts/kconfig/lxdialog/yesno.o
  HOSTCC  scripts/kconfig/mconf.o
  SHIPPED scripts/kconfig/zconf.tab.c
  SHIPPED scripts/kconfig/lex.zconf.c
  SHIPPED scripts/kconfig/zconf.hash.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/mconf
scripts/kconfig/mconf arch/x86/Kconfig
当我们在内核顶层目录执行make menuconfig(假设你知道menuconfig的作用,这里就不多讲了)时,就指定了当前make的对象是menuconfig,那么我们到Makefile中去找到这个目标。注意的是,在众多kbuild系统分析的博客中,都会交代都诸多的细节,我写这个系列的目的主要是为了理出一条清晰的思路,而不去纠缠太多细枝末节的条件判断,当然在最后我会贴出一些比较好的,并且包含多细节的博客分享给大家。

由于我们的目标是menuconfig,在Makefile里面属于一种叫做config-targets的构建对象,在Makefile中会将“include $(srctree)/arch/$(SRCARCH)/Makefile”,即arch/x86/Makefile包含进来,include的动作是相当于把arch/x86/Makefile的内容直接复制到上述语句的所在的地方,成为了当前的Makefile的一部分,自然了,里面的变量也就不需要export出来了。
接下来有一块内容:
%config: scripts_basic outputmakefile FORCE
     $(Q)mkdir -p include/linux include/config
     $(Q)$(MAKE) $(build)=scripts/kconfig $@
这里%config是Makefile里面的通配表示,匹配以config结尾的所以字符,自然我们的menuconfig也是它匹配的类型。它的依赖包括script_basic, outputmakefile,剩下的FORCE,它的作用一句话概括,只要依赖条件中含有FORCE,目标总会被构建。接下来它的构建指令需要重点关注的是第二个(第一条就是创建两个目录),关于变量$(@),这里有详细的介绍。
这句指令中涉及到的$(build)在script/kbuild.include中被定义,它真实的样子是:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
所以通过这个build的定义,上面的那句话可以翻译为:make -f script/Makefile.build obj=script/kconfig menuconfig
实际的执行过程可以到script下的Makefile.build看到:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这三句话就把script/kconfig/目录下的Makefile包含了进来,在这个Makefile中,定义了menuconfig的构建过程:
menuconfig: $(obj)/mconf
     $< $(Kconfig)
我们的讨论环境里,$(Kconfig)指向的是arch/x86/Kconfig文件,这个文件里有啥?很明了,$(obj)/mconf,即script/kconfig/目录下生成的mconf程序会读取arch/x86/Kconfig文件中的内容来生成我们熟悉的配置界面,配置结束之后,在顶层目录下会生成一个名为.config的隐藏文件,这是后续构建过程的重要依据和参考。

关于mconf的生成,前面贴的运行过程已经很清楚了,想了解跟多细节的同学,这里推荐一篇文章:走一走makefile menuconfig流程

依赖条件script_basic和outputmakefile又有怎样的前世今生呢?这里粗略的分析一下。
outputmakefile在我们make时通过”O=“指定了make输出目录才会执行有意义的动作,这里不是我们讨论的情况,先跳过。
script_basic我们可以在主Makefile中找到它:
scripts_basic:
     $(Q)$(MAKE) $(build)=scripts/basic
     $(Q)rm -f .tmp_quiet_recordmcount
主要的动作翻译过来就是:make -f script/Makefile.build obj=script/kconfig,由于没有指定构建对象(即$(build)=script/basic后面为空),所以make的目标就是针对script/Makefile.build的默认目标,很显然它就是“__build”。
这里我跳到重点的片段:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
     @:
这里需要说明的一点就是,在当前的讨论情景下只有always是含有实际对象的,其它的都为空,这里用到的的always是script/basic/Makefile中定义的,在开始时看到执行过程,则是通过Makefile.host产生了一些构建必要的工具,同时将这些工具生成指令写到一个.cmd结尾的文件里,如.docproc.cmd,.fixdep.cmd,.hash.cmd等。
关于@:,在这里有详细的说明。
这篇文章详细的描述了menuconfig的构建过程,上面我所写的这些,貌似重复和多余,但是对我个人而言,关于menuconfig,脑海里保存这些信息就足够了,细节就像是手册中的帮助文档,需要的时候查阅就可以了。
(2) make
直接make,那么就会执行makefile中的默认对象,这里就是vmlinux。
这里我们要提一点,在主Makefile中,include $(srctree)/arch/$(SRCARCH)/Makefile,也就是说将当前架构文件夹下的Makefile包含进来了。在该makfile中bzImage最终还是要以vmlinux为依赖,所以vmlinux是重点。那么vmlinux需要哪些依赖呢?我们列出来看:
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o)

vmlinux-dirs   := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
               $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
               $(net-y) $(net-m) $(libs-y) $(libs-m)))
vmlinux.o: $(modpost-init) $(vmlinux-main)
以上两个是他们各自的依赖,而下面的这几个则是赋值。
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
kallsyms.o := .tmp_kallsyms$(last_kallsyms).o #last_kallsyms是1,2,3等数值
注意这里vmlinux-dirs,后面出现了它的依赖:
$(vmlinux-dirs): prepare scripts
到这里说句题外话,有很多前辈的工作,极大的缩短了我这样刚刚开始研究内核的人的学习曲线,想写点东西,前辈都写的很清楚了,这里就不想重复了。
这里给出云松大牛疯狂内核中的关于内核映像构建相关链接,很前面也很详细。这里主要的内容算是自己的一种总结和理解。
整理一下思路:
1. 各个目录下.o文件的编译生成
$(vmlinux-dirs): prepare scripts
     $(Q)$(MAKE) $(build)=$@
该命令的执行启动了.o文件的编译,由于vmlinux-dirs实际上就是各个目录的替身,在makefile.build中我们看到:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这里的操作就是会依次包含进各个目录下的Makefile,来编译该目录下的对象,编译的实际过程则是:
$(obj)/%.o: $(src)/%.c FORCE
     $(call cmd,force_checksrc)
     $(call if_changed_rule,cc_o_c)
if_changed_rule和cc_o_c是什么?看这里
2. 目录下的.o文件生成built-in.o
下面的命令启动.o连接成built-in.o
$(builtin-target): $(obj-y) FORCE
     $(call if_changed,link_o_target)
这里$(obj-y)是啥?你随便点开一个目录下的Makefile,看看就知道了,其实就是各个.o的集合。
3. 生成vmlinux.o
直接看这里吧,呵呵。
4. vmlinux.lds的生成
.lds文件称为链接脚本,它的语法和作用,参考这里。它在最终链接生成vmlinux起着重要的作用。它的构建规则在Makefile.build中定义:
$(obj)/%.lds: $(src)/%.lds.S FORCE
     $(call if_changed_dep,cpp_lds_S)
5. 链接生成vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
     $(call if_changed_rule,vmlinux__)
这里关于kallsyms.o,可以参考这里。当目前位置,各个目录下的.o都已构建完毕,通过$(call if_changed_rule,vmlinux__)
就可以在顶层目录下生成vmlinux了。
6. 生成bzImage
生成bzImage的工作集中在x86/boot目录和x86/compressed目录中,其中boot目录下的makefile会使用tools/build这个工具将当前目录中生成的setup.bin vmlinux.bin和启动设备号信息(即ROOT_DEV)“打包”成bzImage。
其中boot目录下的setup.ld会将目录下的所有的.o文件连接成setup.elf,然后使用objcopy处理得到setup.bin。
在compressed目录下的makefile会将misc.o,piggy.o,head_32.o或者head_64.o链接成vmlinux,这个vmlinux会在上层boot目录中被objcopy处理生成vmlinux.bin。这里有个奇怪的东西,就是piggy.o,这个东西实际上就是将顶层目录下生成的vmlinux进行了objcopy+gzip处理之后的最终结果。
分享到:
评论

相关推荐

    KBuild MakeFile介绍.doc

    Kbuild系统使用Kbuild Makefile来编译内核或模块。当Kernel Makefile被解析完成后,Kbuild会读取相关的Kbuild Makefile进行内核或模块的编译。Kbuild Makefile有特定的语法指定哪些编译进内核中、哪些编译为模块、及...

    KBUILD 系统原理分析.pdf

    KBUILD用于编译内核,也可以把自己的程序编译进内核。 &lt;br&gt;这是我的课程报告,根据网络资源整理的,希望对大家有帮助。

    嵌入式系统/ARM技术中的kbuild系统-内核模块的编译

    Linux内核是一种单体内核,但是通过动态加载模块的方式,使它的开发非常灵活方便。那么,它是如何编译内核的呢?我们可以通过分析它的Makefile入手。以下是一个简单的hello内核模块的Makefile.  ifneq ($(KERNEL...

    linux内核kbuild Makefile详解

    linux下各平台的下的makefile文件与gnu makefile有一些不一样,这里作了详细分解,有好几个文件,把这个看会了,看linux下makefile不是问题

    疯狂内核之——内核初始化

    2 内核映像的形成 8 2.1 MakeFile预备知识 9 2.1.1 Makefile书写规则 9 2.1.2 Makefile变量 10 2.1.3 条件判断 14 2.1.4 函数 17 2.1.5 隐含规则 17 2.1.6 定义模式规则 19 2.1 KBuild体系 23 2.1.1 内核目标 24 ...

    \\192.168.1.233\george_home\fpga\kbuild_test\kbuild_app.tgz

    kbuild一般编译内核,当前这个工程用于控制编译应用程序,非常不错的例子

    介绍kbuild 的入门文档

    介绍kbuild 的入门文档,很不错,分享一下

    [14本经典Android开发教程]-8-Linux内核阅读心得体会

    读核感悟 kbuild系统 make bzImage的过程 26 读核感悟 kbuild系统 make menuconfig 31 读核感悟 文件系统 用C来实现面向对象 32 读核感悟 设计模式 用C来实现虚函数表和多态 32 读核感悟 设计模式 用C来实现继承和...

    Kbuild分析

    Kbuild系统实现分析,Kconfig和Makefile语法

    kbuild 实现分析--Linux

    本文主要侧重于kbuild的实现分析,希望能从一个building system设计者的角度来更好的了解kbuid的实现和背后的设计思想

    kbuild系统原理

    介绍了kbuild系统原理,讲得比较通俗易懂,适合初学者。

    kbuild makefile 总结

    linux设备驱动makefile:2.4内核模块Makefile模板 #Makefile for linux2.4 KVER=$(shell uname -r) KDIR=/lib/modules/$(KVER)/build OBJS=mymodule.o CFLAGS=-D__KERNEL__ -I$(KDIR) /include -DMODULE

    Linux Kbuild文档

    1.Linux内核配置方式 2.Kconfig 3.Kbuild Makefile 4.一个使用linux Kbuild实现可配置编译的例子

    KBUILD实现pdf

    理解Kbuild有助于理解Linux的编译流程,对于Linux的体系架构理解起到事半功倍的作用

    Linux内核Makefile浅析

    多的资料(《嵌入式Linux应用开发完全手册》、Documentation/kbuild/makefiles.txt)已经向我们展示了一个初级Linux用户者应该懂得的知识--怎样添加需要编译的文件、添加编译的规则、多个源文件构成一个目标文件的...

    linux内核阅读心得

    读核感悟-kbuild系统-make bzImage的过程.....................................26 读核感悟-kbuild系统-make menuconfig........................................31 读核感悟-文件系统-用C来实现面向对象............

    探索Linux内核:Kconfig的秘密

    为了探索Linux内核是如何编译的,本文将深入研究Kconfig/kBuild内部进程,解释.config文件和vmlinux/bzImage文件是如何生成的,并介绍一个用于依赖性跟踪的智能技巧。 Kconfig 构建内核的第一步总是配置。Kconfig...

    Kbuild的实现分析

    本文主要侧重于kbuild 的实现分析,希望能从一个building system 设计者的角度来 更好地了解kbuild的实现和背后的设计思想。

    ca8210-linux:Linux内核驱动程序,用于与Cascoda的CA-8210 IEEE 802.15.4收发器直接进行SPI通信

    构建:必须使用Linux kbuild系统将驱动程序构建为内核模块。 来自 : 构建外部模块的命令是: $ make -C &lt;path&gt; M=$PWD由于命令中提供了“ M = ”选项,kbuild系统知道正在构建外部模块。 要针对正在运行的内核进行...

    kbuild完整详细分析

    非常不错的 Kbuild 分析教程,涉及方面也很多,许多知识点都覆盖到了,作者下了功夫写的,呵呵

Global site tag (gtag.js) - Google Analytics