Linux移植之make uImage編譯過程分析 Linux移植之子目錄下的built-in.o生成過程分析

編譯出uboot能夠運行的linux內核代碼的命令是make uImage,下面詳細介紹下生成linux-2.6.22.6/arch/arm/boot/uImage的過程:html

一、vmlinux、Image、uImage、zImage的區別linux

二、vmlinux生成過程簡介shell

三、uImage生成過程簡介bash

 

一、vmlinux、Image、uImage、zImage的區別,在執行make uImage以後會在%生成以下幾個文件Image、uImage、zImage。函數

vmlinux是可引導的、壓縮的內核。「vm」表明「Virtual Memory」。Linux 支持虛擬內存,不像老的操做系統好比DOS有640KB內存的限制。Linux可以使用硬盤空間做爲虛擬內存,所以得名「vm」。它是elf格式的文件, 編譯內核首先生成的是vmlinux,其它的文件都是基於今生成的。post

Image是vmlinux通過OBJCOPY後生成的純二進制映像文件ui

zImage是Image通過壓縮後造成的一種映像壓縮文件編碼

uImage是在zImage基礎上在前面64字節加上內核信息後的映像壓縮文件,供uboot使用。能夠從文件大小看到1848724-1848660=64字節url

 

二、vmlinux生成過程簡介,make uImage以後最早生成的是vmlinux,由於uImage依賴於vmlinux,在linux-2.6.22.6/arch/arm/Makefile下面有uImage這個目標,能夠看到它依賴於vmlinux,因此先要分析vmlinux的生成過程spa

227    zImage Image xipImage bootpImage uImage: vmlinux
228        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

在linux-2.6.22.6/Makefile頂層Makefile下,定義了vmlinux這個目標

745    vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
746    ifdef CONFIG_HEADERS_CHECK
747        $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
748    endif
749        $(call if_changed_rule,vmlinux__)
750        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
751        $(Q)rm -f .old_version

先逐個分析她的依賴vmlinux-lds、vmlinux-init、vmlinux-main、kallsyms.o、FORCE

 

1)、vmlinux-lds,它是一個連接腳本在連接的時候使用,它跟體系結構相關

611    vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds

 arch/$(ARCH)/kernel/vmlinux.lds一開始是不存在的,它依賴於$(vmlinux-dirs)

755    $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;

vmlinux-dirs這個變量是產生子目錄下built-in.o文件的根源,這個在Linux移植之子目錄下的built-in.o生成過程分析會介紹。

 

2)、vmlinux-init := $(head-y) $(init-y),其中head-y被定義在linux-2.6.22.6/arch/arm/Makefile中:

94    head-y        := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o

init-y被定義在頂層Makefile中:

434 init-y        := init/
573 init-y        := $(patsubst %/, %/built-in.o, $(init-y))

patsubst是Makefile的函數,意思是找到符合%/格式的,而後以%/built-in.o替換,因此最終init-y = init/built-in.o

因此vmlinux-init = arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o

 

3)、vmlinux-main被定義在頂層的Makefile中

609 vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)

相似與vmlinux-init的分析,最終vmlinux-main = usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.a lib/built-in.o drivers/built-in.o sound/built-in.o net/built-in.o

 

4)、kallsyms.o被定義在頂層的Makefile中

679    ifdef CONFIG_KALLSYMS_EXTRA_PASS
680    last_kallsyms := 3
681    else
682    last_kallsyms := 2
683    endif
684
685    kallsyms.o := .tmp_kallsyms$(last_kallsyms).o

頂層的Makefile會包含配置好的.config文件

192    KCONFIG_CONFIG    ?= .config

經查看CONFIG_KALLSYMS_EXTRA_PASS在.config沒有設置,因此last_kallsyms := 3

62 # CONFIG_KALLSYMS_EXTRA_PASS is not set

最終kallsyms.o = .tmp_kallsyms2.o

接着尋找.tmp_kallsyms2.o,一樣在頂層Makefile中

713    .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
714        $(call if_changed_dep,as_o_S)

$(call if_changed_dep,as_o_S)當這條規則被使用時它將檢查哪些文件須要更新,或命令行被改變。同時它會從新檢測依賴關係的改變並將生成新的依賴文件。因此這裏是檢查.o、.S、scripts文件是否被更新過。

scripts的定義以下:

429 PHONY += scripts
430    scripts: scripts_basic include/config/auto.conf
431    $(Q)$(MAKE) $(build)=$(@)

總結一下kallsyms.o依賴的做用就是檢測如下全部生產vmlinux相關的文件是否更新過。

 

5)、FORCE在Linux移植之配置過程分析已經介紹過,每次執行的時候都認爲這個變量是最新的

 

6)、由於CONFIG_HEADERS_CHECK在.config中沒有找到,因此執行的規則爲:

749        $(call if_changed_rule,vmlinux__)
750        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
751        $(Q)rm -f .old_version
$(call if_changed_rule,vmlinux__)檢查規則是否被改變。它的意思是調用if_changed_rule函數,函數參數爲$(1)=vmlinux__。具體分析參考https://blog.csdn.net/zxygww/article/details/50249531它被定義在linux-2.6.22.6\scripts\Kbuild.include中
183    if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
184        @set -e;                                                             \
185        $(rule_$(1)))

這段話的意思是if_changed 函數在當發現規則的依賴有更新,或者是對應目標的命令行參數發生改變時($(if strip $(any-prereq) $(arg-check)) 語句結果不爲空),執行後面的語句。set -e 表示若是命令執行有錯那麼命令中止執行並退出。接着執行 $(cmd_$(1) 裏的命令rule_vmlinux__:它在頂層Makefile定義爲一個shell腳本調用

634    define rule_vmlinux__
635        :
636        $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
637
638        $(call cmd,vmlinux__)
639        $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
640
641        $(Q)$(if $($(quiet)cmd_sysmap),                                      \
642          echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     \
643            $(cmd_sysmap) $@ System.map;                                         \
644        if [ $$? -ne 0 ]; then                                               \
645            rm -f $@;                                                    \
646            /bin/false;                                                  \
647        fi;
648        $(verify_kallsyms)
649        endef

將上述內容實際打印出來獲得

set -e; if [ ! -r .version ]; then rm -f .version; echo 1 >.version; else mv .version .old_version; expr 0$(cat .old_version) + 1 >.version; fi; make -f scripts/Makefile.build obj=init
  CHK     include/linux/compile.h
/bin/bash /work/system/linux-2.6.22.6/scripts/mkcompile_h include/linux/compile.h \
    "arm" "" "" "arm-linux-gcc -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Os -marm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mapcs-32 -mno-thumb-interwork -D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -malignment-traps -msoft-float -Uarm -fno-omit-frame-pointer -fno-optimize-sibling-calls -g  -Wdeclaration-after-statement "
  UPD     include/linux/compile.h
  arm-linux-gcc -Wp,-MD,init/.version.o.d  -nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Os -marm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mapcs-32 -mno-thumb-interwork -D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -malignment-traps -msoft-float -Uarm -fno-omit-frame-pointer -fno-optimize-sibling-calls -g  -Wdeclaration-after-statement     -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(version)"  -D"KBUILD_MODNAME=KBUILD_STR(version)" -c -o init/version.o init/version.c
   arm-linux-ld -EL   -r -o init/built-in.o init/main.o init/version.o init/mounts.o init/initramfs.o init/calibrate.o
  arm-linux-ld -EL  -p --no-undefined -X -o .tmp_vmlinux1 -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group 
echo 'cmd_.tmp_vmlinux1 := arm-linux-ld -EL  -p --no-undefined -X -o .tmp_vmlinux1 -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group ' > ./..tmp_vmlinux1.cmd
  arm-linux-nm -n .tmp_vmlinux1 | scripts/kallsyms  > .tmp_kallsyms1.S
  arm-linux-gcc -Wp,-MD,./..tmp_kallsyms1.o.d -D__ASSEMBLY__ -mapcs-32 -mno-thumb-interwork -D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -msoft-float -gdwarf2   -nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h -mlittle-endian    -c -o .tmp_kallsyms1.o .tmp_kallsyms1.S
  arm-linux-ld -EL  -p --no-undefined -X -o .tmp_vmlinux2 -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group .tmp_kallsyms1.o
  arm-linux-nm -n .tmp_vmlinux2 | scripts/kallsyms  > .tmp_kallsyms2.S
  arm-linux-gcc -Wp,-MD,./..tmp_kallsyms2.o.d -D__ASSEMBLY__ -mapcs-32 -mno-thumb-interwork -D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -msoft-float -gdwarf2   -nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h -mlittle-endian    -c -o .tmp_kallsyms2.o .tmp_kallsyms2.S
  arm-linux-ld -EL  -p --no-undefined -X -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group .tmp_kallsyms2.o
echo 'cmd_vmlinux := arm-linux-ld -EL  -p --no-undefined -X -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group .tmp_kallsyms2.o' > ./.vmlinux.cmd
echo '  /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap  System.map' && /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap vmlinux System.map; if [ $? -ne 0 ]; then rm -f vmlinux; /bin/false; fi;
  /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap  System.map
echo '  /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap  .tmp_System.map' && /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap .tmp_vmlinux2 .tmp_System.map
  /bin/bash /work/system/linux-2.6.22.6/scripts/mksysmap  .tmp_System.map
cmp -s System.map .tmp_System.map || (echo Inconsistent kallsyms data; echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; rm .tmp_kallsyms* ; /bin/false )

咱們的目標是最後生成vmlinux,取出目標vmlinux部分信息

arm-linux-ld -EL  -p --no-undefined -X -o vmlinux -T arch/arm/kernel/vmlinux.lds
arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  
arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c2410/built-in.o  arch/arm/mach-s3c2400/built-in.o  
arch/arm/mach-s3c2412/built-in.o  arch/arm/mach-s3c2440/built-in.o  arch/arm/mach-s3c2442/built-in.o  arch/arm/mach-s3c2443/built-in.o  
arch/arm/nwfpe/built-in.o  arch/arm/plat-s3c24xx/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  
security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  
drivers/built-in.o  sound/built-in.o  net/built-in.o --end-group .tmp_kallsyms2.o

通過連接最終獲得了vmlinux ,能夠看到連接腳本爲arch/arm/kernel/vmlinux.lds,第一個文件爲arch/arm/kernel/head.s

 

 三、uImage生成過程簡介,接着分析生成uImage的過程,這個文件是uboot最終用到的內核文件

在linux-2.6.22.6/arch/arm/Makefile中有以下定義,依賴vmlinux通過第二步已經生成了,接着分析規則。

227    zImage Image xipImage bootpImage uImage: vmlinux
228        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

將規則展開後獲得:

make -f scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/mach-s3c2410/ arch/arm/boot/uImage

直接將這個規則執行後的結果打印出來分析,首先由vmlinux生成二進制文件Image

arm-linux-objcopy -O binary -R .note -R .comment -S  vmlinux arch/arm/boot/Image

接着將Image壓縮成piggy.gz

gzip -f -9 < arch/arm/boot/compressed/../Image > arch/arm/boot/compressed/piggy.gz

接着將解壓縮代碼與壓縮後的linux代碼連接在一塊兒生成arch/arm/boot/compressed/vmlinux,這樣的話從開始地址0x30008000處的程序爲解壓程序的head.S彙編碼,在head.S中會調用arch/arm/boot/compressed/misc.c中的解壓代碼完成解壓,將arch/arm/boot/compressed/piggy.c解壓出來放在物理地址爲0x30008000處。具體解壓過程沒必要關心。

arm-linux-ld -EL   --defsym zreladdr=0x30008000 --defsym params_phys=0x30000100 -p --no-undefined -X /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/libgcc.a -T arch/arm/boot/compressed/vmlinux.lds arch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/misc.o -o arch/arm/boot/compressed/vmlinux 

接着將arch/arm/boot/compressed/vmlinux文件生成二進制文件arch/arm/boot/zImage。

arm-linux-objcopy -O binary -R .note -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

最後在0x30008000地址以前加上64字節的內核信息生成uImage

/bin/bash /work/system/linux-2.6.22.6/scripts/mkuboot.sh -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -n 'Linux-2.6.22.6' -d arch/arm/boot/zImage arch/arm/boot/uImage

以上就是uImage生成過程的反推。最後能夠在linux-2.6.22.6/arch/arm/boot目錄下找到uImage文件。而且會在inux-2.6.22.6\include目錄下生產一個config文件夾,裏面的linux-2.6.22.6\include\config\auto.conf文件是在make uImage一開始就讀取.config文件而後產生的,這個文件供Makefile調用;另外會產生inux-2.6.22.6\include\linux\autoconf.h這個頭文件供內核源碼使用;還有一個include\asm-arm\Mach-types.h產生被內核源碼調用。

相關文章
相關標籤/搜索