Linux-Android启动之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/memory.h>
?
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的生成過程算是可以結束了。
總結
以上是生活随笔為你收集整理的Linux-Android启动之zImage生成过程详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cmd关闭端口的命令是什么(如何开放端口
- 下一篇: wind10优化