arm-linux内核编译过程小结
轉自:https://blog.csdn.net/lidan113lidan/article/details/44981829?spm=1001.2014.3001.5501
記在前面的雜七雜八
通過emulator啟動goldfish的時候,實際上啟動的是zImage,這貨才2.5MB左右,啟動命令如下:
emulator -show-kernel -kernel /mnt/VMDisk1/kernel/goldfish/arch/arm/boot/zImage -avd test -qemu -s- 1
- 1
在圖形化界面下,內核的配置也會有很多很多問題,一般每個系統均提供自定義配置文件,這些配置文件都是與具體芯片相關的(Soc, System on Chip),如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
內核的構建
- 如想使用goldfish的配置,可以:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
-
.config文件是構建內核所需的內核配置目錄,它是在CONFIG_XXX變量中用y,n,m三個狀態進行配置的目錄,這種形態的內核配置系統叫做kconfig。根據kconfig提供的三個狀態(y,n,m)決定是否構建內核相應的模塊(Kconfig系統中y,n,m只是bool類型的配置選項,實際上.config中可能有hex/int/bool/tristate/string這多種類型的選項)。
- 狀態為y時:相應的二進制文件,與vmlinux鏈接。
- 狀態為m時:不會和vmlinux鏈接,但作為模塊執行編譯。
- 狀態為n時:不編譯。
-
mconf通過.config配置文件,生成autoconf.h頭文件
- 1
- 2
- 3
- 1
- 2
- 3
這兩個文件是一樣的,也不知道誰復制的誰,大體看一下文件內容:
#define CONFIG_RING_BUFFER 1 #define CONFIG_NF_CONNTRACK_H323 1 #define CONFIG_KERNEL_GZIP 1 #define CONFIG_INPUT_KEYBOARD 1 #define CONFIG_IP_NF_TARGET_REDIRECT 1 #define CONFIG_CRC32 1 #define CONFIG_NF_NAT_PROTO_SCTP 1 #define CONFIG_HAVE_AOUT 1 #define CONFIG_VFP 1 #define CONFIG_AEABI 1 #define CONFIG_FB_TILEBLITTING 1 #define CONFIG_HIGH_RES_TIMERS 1 #define CONFIG_BLK_DEV_DM 1 #define CONFIG_VLAN_8021Q 1- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
可以發現,在.config中定義的的宏,在預處理階段被處理成了各種#define語句。
-
利用kconfig完成內核配置,準備好.config文件后,即可構建內核。構建內核是指,編譯內核,鏈接各個二進制文件,最終生成一個二進制文件zImage的一系列過程。
-
從linux2.6開始,內核采用kbuild系統來進行編譯了,kbuild是指上是一堆腳本的組合。
linux內核Makefile分類:?
* Kernel Makefile: 位于內核源代碼的頂層目錄,也叫Top Makefile。主要用于指定編譯內核的目標文件(vmlinux)和模塊。在編譯內核或模塊時,這個文件會被首先讀取,并根據內容設置環境變量。?
* kbuild Makefile: kbuild系統使用kbuild Makefile來編譯內核或模塊,Kbuild Makefile指定哪些編譯近內核,哪些編譯為模塊。?
* arch Makefile: 位于./arch/$(ARCH)/Makefile,是系統對應平臺的Makefile。top makefile會包含這個文件來指定平臺相關信息,只有平臺開發人員需要關心這個文件。
vmlinux的生成
編譯后,vmlinux是在內核目錄樹的根目錄下生成的一個ELF文件,這里以goldfish下執行make為例,查看vmlinux的生成。 當執行make命令的時候,會先掃描內核的根目錄的Makefile:
##(后續只列舉關鍵內容),./Makefile ##.PHONY: $(PHONY)是在Makefile最后定義的, .PHONY是將一個目標聲明為偽目標, ##這樣make在執行規則時不會試圖去查找隱含規則來創建他(簡單理解不會把_all當 ##成一個文件,不會存在如果當前目錄存在_all這個文件,而文件不更新,系統不能編譯的問題) ##所有這樣的文件都加到了.PHONY里面。 PHONY := _all ##_all是編譯的默認目標,就是make指令的默認目標 _all: ifeq ($(KBUILD_EXTMOD),) ##如果沒指定編譯模塊 _all: all else ##如果指定是編譯模塊 _all: modules endif #如果沒指定編譯模塊,則這里最終編譯的就是vmlinux #(注:在體系結構相關的makefile中一般還有一個all,即zImage) all: vmlinux vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE##vmlinux-modpost不存在,這里好像是忽略了??$(call vmlinux-modpost)##如果if_changed_rule成立則執行rule_vmlinux__$(call if_changed_rule,vmlinux__)##刪除.old_version$(Q)rm -f .old_version- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
后續會分析其中的各個目標
目標文件 vmlinux.o
vmlinux.o是沒有去除符號表的可執行文件,最終生成的vmlinux為真正的內核鏡像
-rwxr-xr-x 1 tigger tigger 61M 2014-12-22 01:21 vmlinux* -rw-r--r-- 1 tigger tigger 109M 2014-12-22 01:21 vmlinux.o- 1
- 2
- 1
- 2
目標文件 vmlinux.lds
vmlinux.lds是一個鏈接腳本,是給ld鏈接器使用的。一般來說,普通程序是不需要指定linker script的,也不需要關心各個section的具體位置。當程序執行時,kernel中的ELF Loader會根據ELF文件頭解析可執行文件的各個section,并把他們映射到虛擬地址空間。然而,內核啟動時,必須首先確定各個section的具體位置,這就是vmlinux.lds的作用。這個文件必然是體系結構相關的,在arm中有兩個連接腳本分別位于:?
./arch/arm/kernel/vmlinux.lds(這個是給vmlinux編譯用的連接腳本,就是這里面的vmlinux.lds)?
./arch/arm/boot/compressed/vmlinux.lds(這個是給zImage編譯時候用的連接腳本)
目標文件 kallsyms.o
在2.6內核中,為了更好的調試內核,引入了kallsyms機制。kallsyms把內核中用到的所有函數地址和名稱鏈接到內核文件,當內核啟動后,同時加載到內存中。當發生oops時候,內核就會?
解析eip位于哪個函數中,然后打印出backtrace信息。內核編譯的最后,make會執行:nm -n vmlinux|scripts/kallsyms,其中:?
1. nm -n vmlinux負責生成所有的內核符號并按地址排序?
2. scripts/kallsyms負責處理這個列表,并生成需要的鏈接文件tmp_kallsyms%.s?
也就是說kallsyms實際上是內核編譯完了之后,vmlinux中通過nm命令生成的,所以所有符號地址都包括了,實際上是和System.map是一樣的。?
而且kallsyms中所有函數的地址,是放在一個全局數組kallsyms_addresses[]中的,如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
kallsyms的整個符號表,最終都會放在kallsyms.o文件中。
#kallsyms也是最終依賴一個文件,這個是.tmp_kallsymsX.o kallsyms.o := .tmp_kallsyms$(last_kallsyms).o- 1
- 2
- 1
- 2
目標 vmlinux-init
#./Makefile vmlinux-init := $(head-y) $(init-y)- 1
- 2
- 1
- 2
- head-y
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- init-y
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
所以最終vmlinux-init 實際上是:?
1. arch/arm/kernel/head.o(這是Image/vmlinux的入口代碼)。?
2. arch/arm/kernel/init_task.o?
3. init/built-in.o?
三者鏈接而來的。
目標 vmlinux-main
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)- 1
- 1
- core-y
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- libs-y
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 1
- 2
- 3
- drivers-y
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 1
- 2
- 3
- net-y
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
總結一下,vmlinux-main是由以下四個目標組成的:
- core-y:?
- 包含體系結構無關的usr/ kernel/ mm/ fs/ ipc/ security/ crypto/ block/ 目錄下的built-in.o文件(如果是編譯module,則只包含usr/built-in.o)。
- 包含體系結構相關的文件,在arm下為arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ arch/arm/net/下的built-in.o。
- 包含具體芯片相關的文件,如arch/arm/plat-%/ arch/arm/mach-%/下的built-in.o。
- libs-y: 包含arch/arm/lib/和 lib/目錄下的built-in.o和lib.a文件。
- drivers-y: 包含drivers/ sound/ firmware/以及arch/arm/oprofile/(可選)目錄下的built-in.o文件。
- net-y: 包含net/built-in.o文件。
vmlinux的生成過程規則: rule_vmlinux__
define rule_vmlinux__:#makefile -n的時候只是打印命令不會執行,這個+號表示始終執行#這貨生成.version文件舊的.version存到.old_version,內容為"1"$(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))#調用cmd_vmlinux__命令,這個命令實際上就是將vmlinux的一堆依賴目標,連接為vmlinux$(call cmd,vmlinux__)#如果當前$@為DIR/vmlinux,則這個命令被存儲到DIR/.vmlinux.cmd中#@D為$@中的目錄(DIR),@F為$@中的文件(vmlinux)$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd#quiet默認為空(有可能為silent_),為空時調用cmd_sysmap#cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap#這里調用mksysmap來生成System.map,mksysmap就是個腳本,其內容為:#$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2$(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) endefdefine verify_kallsyms$(Q)$(if $($(quiet)cmd_sysmap), \echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \$(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map$(Q)cmp -s System.map .tmp_System.map || \(echo Inconsistent kallsyms data; \echo This is a bug - please report about it; \echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround; \rm .tmp_kallsyms* ; /bin/false ) endef- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
rule_vmlinux__ -> cmd_vmlinux__
#?=是 如果沒有被復制,則等于,這里是調用LD連接vmlinux所需的各種文件#LDFLAGS,LDFLAGS_vmlinux這些變量會作為LD的鏈接參數#-o $@指定最終生成的文件為vmlinuxcmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \# -T指定鏈接腳本文件為vmlinux-lds 后面跟著的$(vmlinux-init)為一堆目標文件-T $(vmlinux-lds) $(vmlinux-init) \##如果ld載入了一個庫,發現該庫中,有UNDF,未被定義的變量,有了這個參數的指示后,就會在這一堆.a和.o文件里面反復搜索,直至找到為止,否則,如果在已經加載的庫中,找不到,就會報錯????--start-group $(vmlinux-main) --end-group \##從$^中去除$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE中的字符,并返回結果,這里的結果就是.tmp_kallsyms2.o(沒用kallsyms.o)$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
rule_vmlinux生成的vmlinux.cmd:
#在mt6582下,vmlinux.cmd如下:cmd_vmlinux := arm-linux-androideabi-ld.bfd \ #$(LD)-EL -p --no-undefined -X --emit-relocs --build-id \ #$LDFLAGS) $(LDFLAGS_vmlinux)-o vmlinux \ #$-o $@-T arch/arm/kernel/vmlinux.lds \ #-T $(vmlinux-lds)arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o \ #$(vmlinux-init)--start-group \usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o mediatek/platform/mt6582/kernel/core/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 firmware/built-in.o mediatek/kernel/built-in.o mediatek/custom/out/kernel/built-in.o mediatek/platform/mt6582/kernel/drivers/built-in.o aliyun/security/built-in.o net/built-in.o \ #$(vmlinux-main)--end-group \.tmp_kallsyms2.o #$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
也就是說vmlinux實際上是由vmlinux.lds 連接vmlinux-init, vmlinux-main和.tmp_kallsyms2.o而成的,與vmlinx.o沒有鏈接的關系!!!
vmlinux.o的生成
#vmlinux.o只依賴于$(modpost-init) $(vmlinux-main)兩個目標文件, ##其最終調用的是rule_vmlinux-modpost vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE$(call if_changed_rule,vmlinux-modpost)define rule_vmlinux-modpost:#調用cmd_vmlinux-modpost,這個函數是用來鏈接生成vmlinux.o的+$(call cmd,vmlinux-modpost)#實際上調用的是make -f $(srctree)/scripts/Makefile.modpost vmlinux.o$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@#dot-target是在$@的前面加個.,這里就是.vmlinux.o.cmd,這里是#將命令存儲到.vmlinux.o.cmd$(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd endif#cmd_vmlinux-modpost負責生成vmlinux.o,其規則和vmlinux的規則差不多#其差別主要在于,vmlinux.o沒有指定--no-undefined編譯選項#沒有指定鏈接腳本,沒有指定符號表cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@ \$(vmlinux-init) --start-group $(vmlinux-main) --end-group \$(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
vmlinux.o的生成命令(.vmlinux.o.cmd)
cmd_vmlinux.o := arm-linux-androideabi-ld.bfd \ #$(LD)-EL \#$(LDFLAGS)-r -o vmlinux.o \# -r -o $@ ,-r指定了可重定位的輸出文件arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o \#$(vmlinux-init)--start-group \usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o mediatek/platform/mt6582/kernel/core/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 firmware/built-in.o mediatek/kernel/built-in.o mediatek/custom/out/kernel/built-in.o mediatek/platform/mt6582/kernel/drivers/built-in.o aliyun/security/built-in.o net/built-in.o \#$(vmlinux-main)--end-group#\$(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)為空- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
make -f $(srctree)/scripts/Makefile.modpost vmlinux.o
rule_vmlinux-modpost生成vmlinux.o后會調用
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@,解析后就是- 1
- 1
解析后就是:
make -f $(srctree)/scripts/Makefile.modpost vmlinux.o- 1
- 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
Module.symvers文件只有在開啟CONFIG_MODVERSIONS才生效的,否則里面的crc全是0,我這里沒有開,內容如下:
<CRC> <Symbol> <module> <type> 0x00000000 cfg80211_send_rx_assoc vmlinux EXPORT_SYMBOL 0x00000000 generic_file_splice_write vmlinux EXPORT_SYMBOL 0x00000000 set_anon_super vmlinux EXPORT_SYMBOL 0x00000000 kmem_cache_alloc vmlinux EXPORT_SYMBOL 0x00000000 replace_page_cache_page vmlinux EXPORT_SYMBOL_GPL 0x00000000 __cond_resched_softirq vmlinux EXPORT_SYMBOL 0x00000000 mt_fh_popod_restore vmlinux EXPORT_SYMBOL 0x00000000 i2c_put_adapter vmlinux EXPORT_SYMBOL 0x00000000 rtc_class_open vmlinux EXPORT_SYMBOL_GPL 0x00000000 scsi_sense_key_string vmlinux EXPORT_SYMBOL ......- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
總結一下:
- vmlinux依賴于目標文件vmlinux.o,但是二者的生成沒有直接關系,即vmlinux并不鏈接vmlinux.o文件
- vmlinux和vmlinux.o的區別主要在于:?
- vmlinux指定了–no-undefined編譯選項,不可以有未決符號,而vmlinux.o可以有。
- vmlinux指定了鏈接腳本vmlinux.lds,vmlinux.o沒有連接腳本。
- vmlinux連接了符號表*kallsyms*.o文件,vmlinux.o沒有連接符號表。
- vmlinux沒指定-r選項,vmlinux.o指定了-r選項,-r是用來生成可重定位的目標文件用的,這個選項導致了vmlinux.o雖然鏈接的較vmlinux少,但實際體積比vmlinux要大(在我編譯出的鏡像中,vmlinux大小61MB,包含56個段; vmlinx.o大小109MB,包含12119個段,其中有6061個段為重定位段,另外有5981個段為各種ksy*段,如__ksymtab_strings。
zImage的生成
#./arch/arm/Makefile #在根目錄makefile中的include $(srctree)/arch/$(SRCARCH)/Makefile會include當前文件 #這是all出現的第二個目標,all的所有目標會合并,合并后就是vmlinux和zImage all: $(KBUILD_IMAGE) KBUILD_IMAGE := zImage #zImage還依賴于vmlinux zImage Image xipImage bootpImage uImage: vmlinux#此命令解析后類似: #make -f scripts/Makefile.build obj=arch/arm/boot MACHINE = XXX arch/arm/boot/zImage#調用makefile.build作為makefile的腳本,obj和MACHINE都為變量#要build的目標為arch/arm/boot/zImage,這個就是target$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 1
- 2
所以zImage實際上是依賴于$(obj)/compressed/vmlinux的,是后者執行了一個objcopy -binary過來的($(obj)/compressed/vmlinux并不是vmlinux,前者是內核Image壓縮為piggy.gz后再次生成的一個壓縮后的elf鏡像,而后者是內核的鏡像,$(obj)/compressed/vmlinux大小約為2.XMB,后面也稱其為vmlinux(小),而另一個稱為vmlinux(大))其命令行如下:
cmd_arch/arm/boot/zImage := arm-linux-androideabi-objcopy -O binary -R .comment -S arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage- 1
- 1
目標?$(obj)/compressed/vmlinux
#./arch/arm/boot/Makefile #vmlinux(小)依賴于Image $(obj)/compressed/vmlinux: $(obj)/Image FORCE#這句和前面類似,還是make -f makefile.build #最終include arch/arm/boot/compressed/makefile#目標$(obj)/compressed/vmlinux定義在arch/arm/boot/compressed/makefile中$(Q)$(MAKE) $(build)=$(obj)/compressed $@ #Image又依賴于vmlinux(大) $(obj)/Image: vmlinux FORCE#Image同樣是vmlinux(大)通過objcopy -binary過來的,.Image.cmd如下:#cmd_arch/arm/boot/Image := arm-linux-androideabi-objcopy \#-O binary -R .comment -S vmlinux arch/arm/boot/Image$(call if_changed,objcopy)@echo ' Kernel: $@ is ready'- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
文件piggy.gzip.s
#此文件直接將piggy.zip包含進來了.section .piggydata,#alloc.globl input_data input_data:.incbin "arch/arm/boot/compressed/piggy.gzip".globl input_data_end input_data_end:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
zImage的生成流程圖
從vmlinux到zImage的步驟如圖:?
*.cmd
- 在構建內核時,各個*.o的目錄下都有一個.*.cmd,這個文件是記錄這個.o最終執行的編譯命令的,如vmlinux.cmd和.vmlinux.o.cmd,從vmlinux到zImage的步驟總結如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
vmlinux.ld
//vmlinux.lds.s用于對ld的輸出進行排版//指定一個特定的輸出機器架構,可以使用arm-XXX-objdump -f來查看一個文件的機器架構 OUTPUT_ARCH(arm) //ENTRY用來設置程序的入口點 ENTRY(_start) SECTIONS { //這個.代表默認的地址計數器,如果一個段沒指定地址,就用當前地址計數 //器的默認地址,這個地址在每次應用于一個段之后,會自加。. = 0;_text = .;.text : {//_start是程序入口地址,被放在了0x00000000的位置,從此可以反向推出,此芯片的上電啟動地址為0x0000000,這個vmlinux.lds用于//生成那個2.6MB的vmlinux,所以這個0x00000000也是最終鏡像zImage的啟動地址。_start = .;*(.start)*(.text)*(.text.*)*(.fixup)*(.gnu.warning)*(.glue_7t)*(.glue_7)}.rodata : {*(.rodata)*(.rodata.*)}.piggydata : {*(.piggydata)}. = ALIGN(4);_etext = .;.got.plt : { *(.got.plt) }_got_start = .;.got : { *(.got) }_got_end = .;.pad : { BYTE(0); . = ALIGN(8); }_edata = .;. = ALIGN(8);__bss_start = .;.bss : { *(.bss) }_end = .;. = ALIGN(8); .stack : { *(.stack) }.stab 0 : { *(.stab) }.stabstr 0 : { *(.stabstr) }.stab.excl 0 : { *(.stab.excl) }.stab.exclstr 0 : { *(.stab.exclstr) }.stab.index 0 : { *(.stab.index) }.stab.indexstr 0 : { *(.stab.indexstr) }.comment 0 : { *(.comment) } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
參考資料
[1].http://lli_njupt.0fees.net/ar01s07.html?ckattempt=1?
[2].http://cache.baiducontent.com/c?m=9d78d513d99d17b8589c837e7b01d6160e54f6743da791532c94d55f92144c413171e2cb72624d4391d27d1716df4e4b9bf62173471456b28cbc8d5dabba85592e9c60742e13dc0754910eaeb85b388465d54de9d848a7e1a461cfb9d2a48e090cd705523cd3abd50d5603cd1ba34862bdedd813544817ceb06472f82d3173c83447c218aab9657900f5b18d0111853dd71545ccf366ee2915c142f940597f1af75bb67c027a66f74853a11f615d85ec29a1702e5724c213ecfb9fe1b41fd09ab977c3a797b828e122a698bbae30036d&p=c46cce10ba904ead08e2977c0908cd&newp=8570c54ad5c145c30be296645b5f88231610db2151d4d31013&user=baidu&fm=sc&query=ld++%2D%2Dstart%2Dgroup%B5%C4%D7%F7%D3%C3&qid=89430f6200031c87&p1=7
總結
以上是生活随笔為你收集整理的arm-linux内核编译过程小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux常用的内核镜像格式
- 下一篇: android 填满手机磁盘空间方法