核心 bzimage 的生成方式

2021-09-22 21:06:27 字數 4020 閱讀 9174

**

在編譯kernel的時候,會編譯出乙個bzimage的檔案,據說這個是可以引導的檔案?

恩,關於這個問題,昨天我還真好好看了一下,發現還真是。玩了核心這麼多年,一直都以為是根目錄下的那個vmlinux是安裝時拷貝到/boot/目錄下的檔案,結果原來不是。真是慚愧慚愧。

我是從make install這個規則開始找下去的。

boot := arch/x86/boot

install:

$(q)$(make) $(build)=$(boot) $@

這個規則在arch/x86/makefile中,好奇為什麼沒有在根makefile裡找到。

那實際上真正執行的是在arch/x86/boot/makefile中這個規則

install:

sh $(srctree)/$(src)/install.sh $(kernelrelease) $(obj)/bzimage \

system.map "$(install_path)"

對應x86架構,在這個install.sh就是arch/x86/boot/install.sh。雖然指令碼中有幾種安裝核心的方式,不過我們只看其中一種也就能確認安裝在/boot/目錄下的是bzimage而不是vmlinux了。

cat $2 > $4/vmlinuz
所以說不看不知道,一看嚇一跳。以後不敢說自己懂核心了。

目標在**?

我們在核心編譯的小目標一文中也提到過,bzimage是x86平台下預設的目標之一。但是並沒有在根目錄的makefile中發現bzimage目標。 而在根目錄的makefile中的前面部分有

include $(srctree)/arch/$(srcarch)/makefile
這個是不同的arch會include不同的檔案,比如是x86的架構就會include arch/x86/makefile

開啟一看,果不其然

# default kernel to build

all: bzimage

好了,我們終於找到這個bzimage的target了,在x86平台它也是all的一部分。

來看看具體是什麼

生成規則

在arch/x86/makefile中,bzimage具體定義是這麼個樣子的。

# kbuild_image specify target image being built

kbuild_image := $(boot)/bzimage

bzimage: vmlinux

ifeq ($(config_x86_decoder_selftest),y)

$(q)$(make) $(build)=arch/x86/tools posttest

endif

$(q)$(make) $(build)=$(boot) $(kbuild_image)

$(q)mkdir -p $(objtree)/arch/$(uts_machine)/boot

$(q)ln -fsn ../../x86/boot/bzimage $(objtree)/arch/$(uts_machine)/boot/$@

又是一坨這麼長的,整的好生心煩。幸好,看到了乙個眼熟的$(make) (bu

ild)

=(build)=

(build

)=(boot) $(kbuild_image)。這個不是我們編譯具體目標的時候經常看到的麼?咱來展開看一眼:

make -f scripts/makefile.build obj=arch/x86/boot arch/x86/boot/bzimage
是不是覺得好像親切了一些?

對scripts/makefile.build檔案再補充一點,在該檔案的開頭處出了包含了scripts/kbuild.include檔案,還包含了乙個$(build-file)檔案。

先來看一下這個變數的定義:

#the filename kbuild has precedence over makefile

kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))

kbuild-file := $(if $(wildcard $(kbuild-dir)/kbuild),$(kbuild-dir)/kbuild,$(kbuild-dir)/makefile)

include $(kbuild-file)

你猜到了什麼不? 沒猜到? 再看一眼上面的注釋?

對了,這個就是單個目錄下符合kbuild系統的規則檔案。

你還記得編譯乙個核心模組時候那個makefile中定義的obj-y, obj-m麼?為什麼我們在核心模組中的規則檔案只需要定義這幾個變數,就可以編譯出目標檔案和模組呢?原因就是在scripts/makefile.build中包含了目標目錄下的規則檔案。

不懂也沒關係,看多了日後自然知曉。

先看一下當前包含的檔案,這次包含的是arch/x86/boot/makefile。裡面有這麼一句。

quiet_cmd_image = build   $@

cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \

$(obj)/zoffset.h $@

$(obj)/bzimage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build force

$(call if_changed,image)

@echo 'kernel: $@ is ready' ' (#'`cat .version`')'

簡單明瞭,會心一笑。

所以最後的最後是通過tools/build這個使用者態工具生成bzimage檔案,而依賴的檔案是setup.bin和vmlinux.bin。

當然加上絕對路徑後,這幾個檔案分別是,

arch/x86/boot/tools/build

arch/x86/boot/setup.bin

arch/x86/boot/vmlinux.bin

arch/x86/boot/zoffset.h arch/x86/boot/bzimage

一張圖顯示依賴關係
setup.bin    vmlinux.bin  

\ /

\ /

bzimage

拷貝setup.bin
dest = fopen(ar**[4], "w");

file = fopen(ar**[1], "r");

c = fread(buf, 1, sizeof(buf), file);

if (fwrite(buf, 1, i, dest) != i)

die("writing setup failed");

先開啟了bzimage,叫dest。

然後讀取setup.bin到buf

最後寫入bzimage

拷貝vmlinux.bin

fd = open(ar**[2], o_rdonly);

kernel = mmap(null, sz, prot_read, map_shared, fd, 0);

/* copy the kernel code */

crc = partial_crc32(kernel, sz, crc);

if (fwrite(kernel, 1, sz, dest) != sz)

die("writing kernel failed");

先開啟了vmlinux.bin

做了一下map

拷貝到了dest指向的bzimage

是不是也挺簡單的呢。

bzimage的兩個組成部分vmlinux.bin和setup.bin又是怎麼出現的呢?

主鍵生成方式

在做搭建ssh專案時,用hibernate反射機制生成pojo以及對映檔案。表主鍵選擇的是uuid,但是程式執行過程中,就報錯了。結果查資料才發現一些問題。大家平時多注意點。在hibernate2.1中,主鍵生成策略中uuid分為uuid.hex和uuid.string,但是從hibernate3....

GUID生成方式

uniqueidentifier guid 字段 在ms sql 資料庫中可以在建立表結構是指定字段型別為uniqueidentifier,並且其預設值可以使用newid 來生成唯一的guid 全域性唯一識別符號 使用newid生成的比較隨機,如果是sql 2005可以使用newsequential...

物件的生成方式

物件的生成方式 拷貝建構函式 用乙個已經存在的物件去初始化另乙個物件時,用到拷貝建構函式。如 class a a a1 a a2 a1 這裡就用到拷貝建構函式 另外 在傳入引數和return返回時,以傳值方式傳遞,需要呼叫拷貝建構函式。需要注意的兩種情況 1 a a1 a a2 a2 a1 並沒有用...