现在的位置: 首页 > 综合 > 正文

linux内核学习(8)如何生成vmlinux?简单走走

2013年09月11日 ⁄ 综合 ⁄ 共 2787字 ⁄ 字号 评论关闭

我们应该了解,内核编译出vmlinux还不算数,最后这个ELF格式的文件会被压缩成bzImage。不过那无关紧要。这次我要说说vmlinux的产
生流程,当然只是简单走走,里面kbuild复杂语法,连Makefile自带的很多规则都是比较复杂的,恐怕要全部搞懂,得费很大劲,毕竟这对于我研究
的方向没有多大帮助。我们知道要产生可执行文件要经过这样几个步骤:xx.c->xx.o、xx.o->xx,即先编译在链接,最终xx就是
我们要的文件,那么内核源代码怎么有序的形成这样的模式呢,靠的就是kbuild这个了不起的框架模型。

当然第一步找到vmlinux目标。

vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
    $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
    $(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
    $(Q)$(MAKE) $(build)=Documentation
endif
    $(call vmlinux-modpost)
    $(call if_changed_rule,vmlinux__)
    $(Q)rm -f .old_version

这个目标依赖的还挺多的,不过这里我只关注2个:vmlinux-init、vmlinux-main。可以看出前面两个是变量。只分析一个即可。
找到vmlinux-init。

vmlinux-init := $(head-y) $(init-y)

这里又有两个变量:head-y、init-y。有些熟悉,有点类似obj-y、obj-m等吧。通过查找,我没找到啊,当然这个Makefile是没有了,这个是和机器有关的变量,在这行上面不远处,有包含:

include $(srctree)/arch/$(SRCARCH)/Makefile

现在应该很熟悉了吧,无非就是将关于机器的那个Makefile给包含进来,这里以x86为例。找到head-y的踪影。

head-y := arch/x86/kernel/head_$(BITS).o
head-y += arch/x86/kernel/head$(BITS).o
head-y += arch/x86/kernel/head.o
head-y += arch/x86/kernel/init_task.o

好了,怎么找,应该知道了。不过这里还来看看init-y会发现和head-y有些不同。至于像.o这些文件怎么产生的,后面会看到。

init-y        := init/

这是第一次定义,但是别太慌,下面还有。

init-y        := $(patsubst %/, %/built-in.o, $(init-y))


句话翻译一下就是 init-y :=
init/built-in.o。这个build-in.o这个中间文件可能听说过,其实这个文件就是有这个目录下所有obj-y来合成的。当然会用到递
归调用的方式,不过怎么个递归法不是我要探讨的问题,我只需要找到在哪里开始的就ok。好了,vmlinux-init基本就可以确定了,下面的
vmlinux-main类似方式可以确定。我在来说说比较关键的一个问题,build-in.o是在哪条命令中产生,因为我们知道肯定得涉及
kbuild规则递归调用才能做到。其实要知道这个在哪里产生的确得看些东西才能找到,不过这里我只是简单说说就可以了。知道这句话就可以了。

$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;

这句在执行vmlinux目标前由依赖关系产生,我们来看看最关键的vmlinux-dirs。

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-dirs)还是一个目标。

PHONY += $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@

翻译一下,就知道用到了Makefile.kbuild规则。将vmlinux-dirs里面的目录进行了递归处理产生出我们之前说的那些.o的文件,特别是build-in.o

果不了解一些常识,谁会注意到sort那句话就是干这事情的。所以在执行vmlinux时候,$(vmlinux-dirs)目标肯定会先得到执行,现在
该有的都有了,vmlinux-init、vmlinux-main,关键的内容都来,最后执行链接即可得到vmlinux,在哪里链接的,看看
endif后面那3条。

endif
    $(call vmlinux-modpost)
    $(call if_changed_rule,vmlinux__)
    $(Q)rm -f .old_version

第一条就是调用一下vmlinux-modpost,这个其实也是个命令,只不过是自定义的。查找一下,在上面。

quiet_cmd_vmlinux-modpost = LD      $@
      cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@                          /
     $(vmlinux-init) --start-group $(vmlinux-main) --end-group             /
     $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
define rule_vmlinux-modpost
    :
    +$(call cmd,vmlinux-modpost)
    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
    $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd
endef


发现没有,既定义了命令还定义了规则,$(LD)就是链接了。呵呵,说得够简单的,说到这里发现,整个过程竟然如此简单,但是要分析到这些得看很多内容的,发现我搞2天呢。呵呵,不还是蛮值得的。

抱歉!评论已关闭.