Chinaunix首页 | 论坛 | 博客
  • 博客访问: 58705
  • 博文数量: 20
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-29 01:11
文章分类
文章存档

2011年(1)

2010年(19)

我的朋友

分类: LINUX

2010-03-18 17:27:08

linux zImage生成过程详解


 
可以看到,在顶层makefile的第278行,包含了scripts/Kbuild.include文件,在这里定义了大量的函数和变量,供顶层makefile和其他makefile文件使用。
  
在顶层makefile文件的第412行,包含了arch/arm/Makefile。这个是体系结构相关makefile文件。它定义了体系结构相关的一些变量及规则。
  
当执行”make”时,arch/arm/Makefile中的185行的规则将是make遇到的第一个规则:
  
all:   $(KBUILD_IMAGE)
  
KBUILD_IMAGE这个变量是arch/arm/Makefile的第182行定义。
  
KBUILD_IMAGE := zImage
  
然后看zImage的构建规则,在arch/arm/Makefile的第212行开始定义
  
zImage Image xipImage bootpImage uImage: vmlinux
       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
  
build变量在scripts/Kbuild.include文件中第114行定义:
  
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
  
boot变量在arch/arm/Makefile的187行定义:
  
boot := arch/arm/boot
  
MACHINE变量的值在arch/arm/Makefile的147行开始定义
  
ifneq ($(machine-y),)
MACHINE  := arch/arm/mach-$(machine-y)/
else
MACHINE  :=
endif
  
这里machine-y := s3c2410,所以变量MACHINE的值为
  
MACHINE  := arch/arm/mach-s3c2410
  
所以上面的规则可写为如下形势
  
  
zImage: vmlinux
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= \
       arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
  
这个规则的依赖是vmlinux,下面先看看这个依赖目标的创建规则。
  
vmlinux目标的规则在顶层Makefile的第738行定义。
  
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
       $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
       $(call if_changed_rule,vmlinux__)
       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
       $(Q)rm -f .old_version
  
这里涉及到几个变量,先看看这几个变量的定义,前三个变量分别在605、602、603行定义。
  
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
  
其中head-y在arch/arm/Makefile中第89行定义,
  
head-y            := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
  
init-y在顶层makefile的433行定义
  
init-y              := init/
  
后又在第567行进行处理
  
init-y              := $(patsubst %/, %/built-in.o, $(init-y))
  
所以变量init-y应为
  
init-y              := init/built-in.o
  
因此
  
vmlinux-init := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o init/built-in.o
  
同理,其他几个变量也可通过类似方法进行分析,这里不一一分析了。vmlinux-init这个变量的构建规则在748行定义:
  
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
  
这里是一个空命令的规则。空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令。其依赖为vmlinux-dirs,这个变量在顶层Makefile第558行定义:
  
vmlinux-dirs   := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                   $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
                   $(net-y) $(net-m) $(libs-y) $(libs-m)))
  
这个变量指定了一系列要进入的下层目录。他的规则在顶层Makefile第757行定义
  
$(vmlinux-dirs): prepare scripts
       $(Q)$(MAKE) $(build)=$@
  
这里的两个依赖就不分析了,主要看一下这个规则的命令,build和$@变量展开后如下
  
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build  \
        obj =$(vmlinux-dirs)
  
这里会再一次进入scripts/Makefile.build执行83行规则
  
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
        $(if $(KBUILD_MODULES),$(obj-m)) \
        $(subdir-ym) $(always)
       @:
  
因为KBUILD_BUILTIN在顶层Makefile中被初始化为1,所以这个规则的依赖有一个builtin-target变量。这个变量在scripts/Makefile.build的78行定义
  
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
  
变量obj就是vmlinux-dirs变量指定的目录。所以这里会构建$(vmlinux-dirs)/built-in.o目标,在scripts/Makefile.build文件的261行开始,有这个目标的规则及命令的定义
  
ifdef builtin-target
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
                    $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\
                    rm -f $@; $(AR) rcs $@)
  
$(builtin-target): $(obj-y) FORCE
       $(call if_changed,link_o_target),
  
scripts/Makefile.build在第16行开始包含了vmlinux-dirs变量指定目录中的Makefile文件,在这些makefile文件中会指定obj-y变量,它指定的都是一些*.o目标文件,
  
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
  
这些*.o文件的生成方法由scripts/Makefile.build文件202行的模式规则指定
  
%.o: %.c FORCE
       $(call cmd,force_checksrc)
       $(call if_changed_rule,cc_o_c)
  
通过上面这一系列的步骤,就编译链接出由变量vmlinux-init指定的目标,vmlinux-main变量指定的目标的构建与此类似。再看看vmlinux的构建规则
  
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
       $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
       $(call if_changed_rule,vmlinux__)
       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
       $(Q)rm -f .old_version
  
现在vmlinux的依赖都处理好了,开始执行这个规则的命令,命令
  
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
  
是进行头文件的相关检测,这里不作详细分析。看第二条命令
  
       $(call if_changed_rule,vmlinux__)
  
这里通过函数调用,执行rule_vmlinux__,在顶层Makefile第636行开始定义
  
define rule_vmlinux__
       :
       $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
  
       $(call cmd,vmlinux__)
       $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
  
       $(Q)$(if $($(quiet)cmd_sysmap),                                      \
         echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     \
       $(cmd_sysmap) $@ System.map;                                         \
       if [ $$? -ne 0 ]; then                                               \
              rm -f $@;                                                    \
              /bin/false;                                                  \
       fi;
       $(verify_kallsyms)
endef
  
这里主要还是调用cmd_vmlinux__,定义在顶层Makefile的610行
  
      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
      -T $(vmlinux-lds) $(vmlinux-init)                          \
      --start-group $(vmlinux-main) --end-group                  \
      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
  
通过这个命令将变量vmlinux-init和vmlinux-main指定的目标链接成vmlinux文件。链接脚本由vmlinux-lds指定。在顶层 Makefile 605行定义:
  
vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
  
现在再看一下zImage的构建规则
  
zImage: vmlinux
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= \
       arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
  
其依赖vmlinux已经构建完成,它的命令同样是执行scripts/Makefile.build文件,它的开头包含了arch/arm/boot/Makefile文件,在这个文件的第56行开始就是arch/arm/boot/zImage的构建规则:
  
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
       $(call if_changed,objcopy)
       @echo '  Kernel: $@ is ready'
  
变量obj的值就是arch/arm/boot,前面已经分析过。其依赖  $(obj)/compressed/vmlinux的构建规则在arch/arm/boot/Makefile的53行开始定义的
  
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
  
这个规则的依赖$(obj)/Image的构建规则在arch/arm/boot/Makefile的49行开始定义:
  
$(obj)/Image: vmlinux FORCE
       $(call if_changed, objcopy)
       @echo '  Kernel: $@ is ready'
  
在这个规则中,将前面创建的vmlinux文件通过二进制工具objcopy进行处理,在scripts/Makefile.build的第19行包含了scripts/Makefile.lib
  
include scripts/Makefile.lib
  
在这个makefile文件中,有cmd_objcopy的定义,在156行开始定义
  
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $
  
asm是一个符号,链接到asm-arm上的
  
在arch/arm/Makefile第140行,有
  
TEXT_OFFSET := $(textofs-y)
  
第90行有
  
textofs-y := 0x00008000
  
所以TEXT_OFFSET := 0x00008000
  
在153行有export TEXT_OFFSET将此变量输出。这样arch/arm/kernel/vmlinux.lds.S也就获得了PAGE_OFFSET + TEXT_OFFSET的值。
  
  
现在看看arch/arm/boot/compressed/makeflie生成的vmlinux。它是根据arch/arm/boot /compressed/vmlinux.lds链接脚本生成的。这个脚本由arch/arm/boot/compressed /vmlinux.lds.in生成,在这个文件的开始处有
  
  . = TEXT_START;
  
现在看arch/arm/boot/compressed/Makefile,在110行有
  
$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
       @sed "$(SEDFLAGS)"
阅读(943) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~