日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)

發(fā)布時(shí)間:2025/3/12 linux 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

內(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)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。