可以看到,在頂層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的產生過程算是可以結束了。