刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)
內(nèi)核根目錄下的vmlinux映像文件是內(nèi)核Makefile的默認(rèn)目標(biāo)。這個(gè)vmlinux映像的生成可以通過(guò)閱讀內(nèi)核Makefile文件得知,簡(jiǎn)單的說(shuō):Makefile解析內(nèi)核配置文件.config,遞歸到各目錄下編譯出.o文件,最后將其鏈接成vmlinux。而這個(gè)鏈接成的vmlinux文件是一個(gè)包含內(nèi)核代碼的靜態(tài)可執(zhí)行ELF文件,你可以通過(guò)file命令來(lái)驗(yàn)證這一點(diǎn)。她不能通過(guò)bootloader引導(dǎo)并啟動(dòng),如果想要使其可引導(dǎo),必須使用編譯工具鏈中的objcopy命令把這個(gè)ELF格式的vmlinux轉(zhuǎn)化為二進(jìn)制格式才行。
而平常使用的zImage文件就是這個(gè)vmlinux文件經(jīng)過(guò)多次的轉(zhuǎn)換得到的。現(xiàn)在就來(lái)仔細(xì)研究一下她的生成過(guò)程。
(1)arch/$(ARCH)/Makefile
首先嵌入式中經(jīng)常使用的編譯目標(biāo)zImage并不在頂層Makefile文件中,而在被頂層Makefile包含的arch/$(ARCH)/Makefile文件中,對(duì)于ARM處理器來(lái)說(shuō)就是arch/arm/Makefile文件。其中的部分規(guī)則如下:
……
# Default target when executing plain make
ifeq ($(CONFIG_XIP_KERNEL),y)
KBUILD_IMAGE := xipImage
else
KBUILD_IMAGE := zImage
endif
all:$(KBUILD_IMAGE)
boot := arch/arm/boot
archprepare:
$(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
# Convert bzImage to zImage
bzImage: zImage
zImage Image xipImage bootpImage uImage:vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
……
從這里可以看出,zImage的依賴是頂層vmlinux文件,下面的命令展開得到:
make -f scripts/Makefile.build obj= arch/arm/boot MACHINE=arch/arm/mach-* arch/arm/boot/ zImage
可以看出zImage其實(shí)是make解析arch/arm/boot目錄下的Makefile文件生成的,而參數(shù)傳遞了目標(biāo)芯片信息和目標(biāo)“arch/arm/boot/zImage”。所以zImage其實(shí)是在arch/arm/boot目錄下完成編譯的,這就是為什么可引導(dǎo)zImage映像會(huì)在arch/arm/boot目錄下。
(2)arch/$(ARCH)/boot/Makefile
現(xiàn)在來(lái)分析一下arch/arm/boot/Makefile中的部分規(guī)則,看看目標(biāo)zImage的生成:
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
$(obj)/zImage:$(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
先看最后一行,從中可以得知arch/arm/boot/zImage的依賴目標(biāo)是arch/arm/boot/ compressed/vmlinux,且目標(biāo)zImage是其二進(jìn)制化的產(chǎn)物。
而arch/arm/boot/compressed/vmlinux是如何得到的呢?再看上一規(guī)則,arch/arm/boot/compressed/vmlinux的依賴目標(biāo)是arch/arm/boot/Image。這個(gè)依賴目標(biāo)的生成由最上面的規(guī)則決定,顯然arch/arm/boot/Image是由頂層vmlinux二進(jìn)制化得到的。而中間這行規(guī)則的含義是arch/arm/boot/compressed/vmlinux由make解析arch/arm/boot/compressed/目錄下的Makefile文件生成的,這條命令展開得到:
make -f scripts/Makefile.build obj= arch/arm/boot/compressed arch/arm/boot/compressed/vmlinux
(3)arch/$(ARCH)/boot/compressed/Makefile
最后就來(lái)分析一下arch/arm/boot/compressed/Makefile中的部分規(guī)則,看看arch/arm/boot/compressed/vmlinux 的生成:
......
suffix_$(CONFIG_KERNEL_GZIP) = gzip
suffix_$(CONFIG_KERNEL_LZO) ?= lzo
suffix_$(CONFIG_KERNEL_LZMA) = lzma
......
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
$(call if_changed,ld)
@$(check_for_bad_syms)
$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
$(call if_changed,$(suffix_y))
$(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE
......
上面的第一條規(guī)則就說(shuō)明了:其實(shí)arch/arm/boot/compressed/vmlinux是由幾個(gè)部分根據(jù)arch/arm/boot/compressed/vmlinux.lds 腳本鏈接而成的:
$(obj)/$(HEAD):arch/arm/boot/compressed/head.o,在鏈接時(shí)處于vmlinux的最前面,其主要作用就是做一些必要的初始化工作,如初始化CPU、中斷描述符表IDT 和內(nèi)存頁(yè)目錄表GDT等等,最后跳到misc.c中的decompress_kernel函數(shù)進(jìn)行內(nèi)核的自解壓工作。
$(addprefix $(obj)/, $(OBJS)):arch/arm/boot/compressed/ misc.o,位于head.o之后,是內(nèi)核自解壓的實(shí)現(xiàn)代碼。
以下假定是gzip模式壓縮:
$(obj)/piggy.$(suffix_y).o:arch/arm/boot/compressed/ piggy.gzip.o,其實(shí)是arch/arm/boot/Image經(jīng)過(guò)gzip壓縮后(piggy.gzip),再借助piggy.gzip.S一起編譯出的ELF可鏈接文件。其中的原理可以看看piggy.gzip.S源碼:
.section .piggydata,#alloc
.globlinput_data
input_data:
.incbin"arch/arm/boot/compressed/piggy.gzip"
.globlinput_data_end
input_data_end:
這里我還是要額外的提一下gzip壓縮,也就是$(call if_changed,$(suffix_y))這個(gè)過(guò)程。這個(gè)命令認(rèn)真解析起來(lái)比較麻煩,這里如果有興趣的讀者可以自行分析。這里介紹兩篇經(jīng)典的分析文檔:《kbuild實(shí)現(xiàn)分析》、《Kbuild系統(tǒng)原理分析》,讀者可自行上網(wǎng)下載學(xué)習(xí)。這里我直接給出了結(jié)果,這條命令執(zhí)行了在Makefile.lib(scripts)中定義的:
cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
(rm -f $@ ; false)
也就是說(shuō),piggy.gzip是將arch/arm/boot/Image文件cat到標(biāo)準(zhǔn)輸出,并通過(guò)管道傳入gzip命令(gzip -n -f -9)的標(biāo)準(zhǔn)輸入,最后將gzip的輸出重定向到目標(biāo)piggy.gzip
而這個(gè)piggy.gzip文件有一個(gè)重要的特性:最后的四個(gè)字節(jié),是文件壓縮前的大小數(shù)據(jù),存放格式是小端模式。這個(gè)數(shù)據(jù)在zImage自解壓時(shí)會(huì)被用于程序得到內(nèi)核解壓后所需要的空間!!!
感興趣的朋友可以自己隨便用“gzip -n -f -9”壓縮一個(gè)文件試試,驗(yàn)證一下,我已親自驗(yàn)證過(guò)了。
這樣跟蹤下來(lái),zImage的產(chǎn)生過(guò)程已經(jīng)看完了,但是讀者可能會(huì)被這有點(diǎn)復(fù)雜的關(guān)系繞暈了,所以現(xiàn)在可以結(jié)合一下的流程圖簡(jiǎn)單地總結(jié)一下:
首先頂層vmlinux是ELF格式的可執(zhí)行文件,必須將其二進(jìn)制化生成Image后才可以被bootloader引導(dǎo)。為了實(shí)現(xiàn)壓縮的內(nèi)核映像,arch/arm/boot/compressed/Makefile又將這個(gè)非壓縮映像Image做gzip壓縮,生成了piggy.gzip。但要實(shí)現(xiàn)在啟動(dòng)時(shí)自解壓,必須將這個(gè)piggy.gzip轉(zhuǎn)化為.o文件,并同初始化程序head.o和自解壓程序misc.o一同鏈接,生成arch/arm/boot/compressed/vmlinux。最后arch/arm/boot/Makefile將這個(gè)ELF格式的arch/arm/boot/compressed/vmlinux二進(jìn)制化得到可被bootloader引導(dǎo)的映像文件zImage。
總結(jié)
以上是生活随笔為你收集整理的刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多线程CreateThread函数的用法
- 下一篇: Boolean()