Linux-Android啟動之zImage產生過程詳解

來源:互聯網
上載者:User

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.