linux 生成image,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)) $< $@

变量OBJCOPY在顶层Makefile中289行定义:

OBJCOPY             = $(CROSS_COMPILE)objcopy

OBJCOPYFLAGS变量在arch/arm/Makefile中第15行定义

OBJCOPYFLAGS  :=-O binary -R .note -R .comment –S

所以命令cmd_objcopy可扩展为

cmd_objcopy = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment –S $< $@

这就是处理vmlinux的命令。然后看看规则

$(obj)/compressed/vmlinux: $(obj)/Image FORCE

$(Q)$(MAKE) $(build)=$(obj)/compressed $@

的命令行,变量扩展后为:

$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= \

$(obj)/compressed $(obj)/compressed/vmlinux

于是在scripts/Makefile的开头会包含arch/arm/boot/compressed/Makefile文件,并执行其中的$(obj) /vmlinux目标所在的规则,在这个Makefile文件的第98行开始定义:

$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \

$(addprefix $(obj)/, $(OBJS)) FORCE

$(call if_changed,ld)

@:

这里先看$(obj)/piggy.o,在arch/arm/boot/compreseed/Makefile的103行开始

$(obj)/piggy.gz: $(obj)/../Image FORCE

$(call if_changed,gzip)

$(obj)/piggy.o:  $(obj)/piggy.gz FORCE

这两个规则的第一个就是把由vmlinux生成的Image进行压缩生成piggy.gz,然后生成piggy.o

cmd_ld命令在scripts/Makefile.lib文件149行定义:

quiet_cmd_ld = LD      $@

cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) \

$(filter-out FORCE,$^) -o $@

这里根据链接脚本arch/arm/boot/compressed/vmlinux.lds链接生成了arch/arm/boot/compressed/vmlinux文件。然后在arch/arm/boot/Makefile的第56行的规则中

$(obj)/zImage: $(obj)/compressed/vmlinux FORCE

$(call if_changed,objcopy)

@echo '  Kernel: $@ is ready'

经过objcopy处理后便生成的最终的zImage 。

下面看一下顶层Makefile生成的vmlinux以及arch/arm/boot/compressed/makefile生成的vmlinux的起始地址。

通过顶层Makefile中的规则生成vmlinux是根据arch/arm/kernel/vmlinux.lds这个脚本链接生成的。arch/arm/kernel/vmlinux.lds是由arch/arm/kernel/vmlinux.lds.S生成的,其生成规则在scripts/Makefile.build的第246行开始定义

quiet_cmd_cpp_lds_S = LDS     $@

cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<

%.lds: %.lds.S FORCE

$(call if_changed_dep,cpp_lds_S)

在arch/arm/kernel/vmlinux.lds.S的开始处有

#ifdef CONFIG_XIP_KERNEL

. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);

#else

. = PAGE_OFFSET + TEXT_OFFSET;

#endif

我们这里的起始地址就是PAGE_OFFSET + TEXT_OFFSET。

在include/asm-arm/memory.h的49行开始有

#ifndef PAGE_OFFSET

#define PAGE_OFFSET        UL(0xc0000000)

#endif

而arch/arm/kernel/vmlinux.lds.S的开头有

#include 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)" < $ $@

这就是由vmlinux.lds.in生成vmlinux.lds的规则,在它的命令中有个变量SEDFLAGS,在74行定义

SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/

这里就把TEXT_START换成了ZTEXTADDR。再往上看从66行起

ifeq ($(CONFIG_ZBOOT_ROM),y)

ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)

ZBSSADDR    := $(CONFIG_ZBOOT_ROM_BSS)

else

ZTEXTADDR := 0

ZBSSADDR    := ALIGN(4)

endif

如果zImage是从ram中启动ZTEXTADDR      := 0,否则从rom或flash启动时ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT),这里要在配置时设定CONFIG_ZBOOT_ROM_TEXT的值。

到这里,关于zImage的生成过程算是可以结束了。

阅读(405) | 评论(0) | 转发(0) |

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值