vmlinux是如何煉成的-- kernel makefile
引子
kern e l的ma kefi l e包含的 內容還真 是多,我 就是想看 看要是我 自己添加 一個目錄 編譯到內 核裡,要 怎麼做 。
就是這麼 個不起眼 的實驗, 引發了一 堆的故事 。
最簡單的例子
添加 一個目錄,叫test, 添加了test.c 和 Makefile。
文件內容很簡單,如下。
cat Makefile
#
# Makefile for the linux kernel makefile experiment.
#
# Makefile for the linux kernel makefile experiment.
#
obj-y := test.o
cat test.c
#include <linux/export.h>
int test_global = 0;
然後在主 Makefile中 添加
-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
+core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
最後 make test
make[1]: Nothing to be done for `all'.
HOSTCC arch /x86 /too ls/r eloc s
CHK incl ude/ linu x/ve rsio n.h
CHK incl ude/ gene rate d/ut srel ease .h
CC kernel/bounds.s
GEN incl ude/ gene rate d/bo unds .h
CC arch /x86 /ker nel/ asm- offs ets. s
GEN incl ude/ gene rate d/as m-of fset s.h
CALL scri pts/ chec ksys call s.sh
CC test/test.o
LD test/built-in.o
HOSTCC arch
CHK incl
CHK incl
CC kernel/bounds.s
GEN incl
CC arch
GEN incl
CALL scri
CC test/test.o
LD test/built-in.o
恩,不錯,可以了。
vmlinux是如何煉成的-- kernel makefile
人總是不 知足的, 我又開始 好奇,這 個bui l d的過程 究竟是怎 麼個回事 。
好吧,我 們知 道mak e後,最 終的結果 叫vml inu x,那我 們就找找 這個神奇 的東西是 怎 麼
產生的吧。
vmlinux-deps := $(KBUILD_LDS) $(KB UILD _VML INUX _INI T) $(KB UILD _VML INUX _MAI N)
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
vmlinux: scri pts/ link -vml inux .sh $(vmlinux-deps) FORCE
ifdef CONF IG_H EADE RS_C HECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
$(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
$(Q)$(MAKE) $(bu ild) =Doc umen tati on
endif
+$(call if_c hang ed,l ink- vmli nux)
vmlinx 基於上面三個目標, 而vmlinux-deps又基於 $(vmlinux-dirs)。 恩,好複雜。
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
$(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
$(Q)$(MAKE) $(bu
endif
+$(call if_c
vmlinx 基於上面三個目標, 而vmlinux-deps又基於 $(vmlinux-dirs)。 恩,好複雜。
那來看 看vml inux -dir s都包含 什麼吧。
在主Makefile中看到下面的內容。
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
$(Q)$(MAKE) $(build)=$@
恩, 我們 把vml inux -dir s的東東 打印出來 看看。
vmlinux-dris: init usr arch/x86 kernel mm fs ipc security crypto block test drivers sound firmware arch/x86/pci arch/x86/power arch/x86/video arch/x86/oprofile net lib arch/x86/lib
這樣,你是不是明白點了呢。 這些都 是ker ne l源代碼 中子目錄 。也就 是ker ne l將要挨 個 的
進入每個子目錄,編譯~。
那最後這 個vml inu x是怎麼 生成的呢 ? 怎麼樣將 每個目錄 下生成的 模塊鏈接 成一 個vml inu x的文件 的呢 ?
看到上 面vml inu x目標中 ,最後一 個命令 :
+$(call if_c hang ed,l ink- vmli nux)
哦,原來 是調用 了cmd _lin k-vm linu x。這個 命令就定 義在 主Mak efil e中 。
cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
打出來看看,長這樣。
/bin/bash $< ld -m elf_i386 --emit-relocs --build-id
$< 表示第一 個以來目 標,那麼 在vml inu x目標中 ,第一個 目標是 scri pts/ link -vml inux .sh, 展開後就成為。
/bin/bash scri pts/ link -vml inux .sh ld -m elf_i386 --emit-relocs --build-id
額,原來是又調用了一個腳本。。。 好吧, 再進去看看。 發現這麼個東東
info LD vmlinux
vmlinux_link "${kallsymso}" vmlinux
vmlinux_link "${kallsymso}" vmlinux
vmlinux_link()
{
local lds= "${o bjtr ee}/ ${KB UILD _LDS }"
if [ "${SRCARCH}" != "um" ]; then
${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
-T ${lds} ${KB UILD _VML INUX _INI T} \
--start-group ${KB UILD _VML INUX _MAI N} --end-group ${1}
else
${CC} ${CFLAGS_vmlinux} -o ${2} \
-Wl,-T,${lds} ${KB UILD _VML INUX _INI T} \
-Wl ,--s tart -gro up \
${KB UILD _VML INUX _MAI N} \
-Wl ,--e nd-g roup \
-lutil ${1}
rm -f linux
fi
}
local lds=
if [ "${SRCARCH}" != "um" ]; then
${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}
-T ${lds} ${KB
--start-group ${KB
else
${CC} ${CFLAGS_vmlinux} -o ${2}
-Wl,-T,${lds} ${KB
-Wl
${KB
-Wl
-lutil ${1}
rm -f linux
fi
}
好吧,原來是調用了這個函數。。。 打出來看看吧。
ld -m elf_i386 --emit-relocs --build-id -o vmlinux -T arch /x86 /ker nel/ head _32. o arch /x86 /ker nel/ head 32.o arch /x86 /ker nel/ head .o init/built-in.o --start-group usr/built-in.o arch/x86/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 test/built-in.o lib/lib.a arch/x86/lib/lib.a lib/built-in.o arch /x86 /lib /bui lt-i n.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch /x86 /pci /bui lt-i n.o arch /x86 /pow er/b uilt -in. o arch /x86 /vid eo/b uilt -in. o net/built-in.o --end-group .tmp_kallsyms2.o
恩,原來真相是這樣的。 最後把這 麼多東西 鏈接起來 成 為vml inu x。 看到我們 添加 的tes t目錄了 麼,它也 生成了一 個bui lt-i n. o,最後 鏈接到 了vml inu x中 。
$ nm vmlinux | grep test_global
c198d284 B test_global
啊哦,還真有這個symbol!
啊哦,還真有這個symbol!
神秘的built-in.o
在最後的 鏈接過程 中,我們 可以看到 ,幾乎所 有的依賴 條件中, 都會生成 一 個bui lt-i n. o的文件 。 那這個文件,是怎麼生成的呢?
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
$(Q)$(MAKE) $(build)=$@
從這個規 則中可以 看到 ,vml inux -di r目標是 通過下面 的mak e來生成 的。展開 一下看看 。 這 個bui l d在sc ript s/Kb uild .inc lud e中 。
make -f scri pts/ Make file .bui ld obj=$@
對應到test目錄 那就是
make -f scri pts/ Make file .bui ld obj=test
這麼看來 ,就要進 到scr ipts /Mak efil e.bu il d文件了 。
PHONY := __build
__build:
__build:
__build: $(if $(KB UILD _BUI LTIN ),$ (bui ltin -tar ge t) $(lib-target) $(extra-y)) \
$(if $(KB UILD _MOD ULES ),$( obj- m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
$(subdir-ym) $(always)
@:
__bu il d是這 個mak efil e的第一 個目標, 也是默認 的目標。 這裡面藏 著一 個bui ltin -tar ge t,看著 很像,再 搜搜 。
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
endif
恩 原來這個 就是這麼 多 叫bui lt-i n. o的原因 。但是要 生 成bui t-in . o,必須 要以上的 這些變量 不能全部 為空 。
那再來看 看編譯這 個bui lt-i n. o的規則 是什 麼
quie t_cm d_li nk_o _tar get = LD $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cm d_se cana lysi s),\
rm -f $@; $(AR) rcs$ (KBU ILD_ ARFL AGS) $@)
$(builtin-target): $(obj-y) FORCE
$(call if_c hang ed,l ink_ o_ta rget )
targets += $(builtin-target)
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cm
rm -f $@; $(AR) rcs$
$(builtin-target): $(obj-y) FORCE
$(call if_c
targets += $(builtin-target)
恩,基本 明白了, 就是 當obj - y的內容 不為空, 那麼就 用l d來鏈接 成一 個bui lt-i n. o。
但是我試 了一下, 如果沒 有obj - y那麼, 也會生成 一 個bui lt-i n. o,但是 用的是別 的命令 。
如在i386下,用的是
rm -f test/built-in.o; ar rcsD test/built-in.o
不知道這個是什麼高級玩意。
好了,到 此為止, 基本上一 個最上層 的框架有 了一個概 念。 那就先休息一下~
一切盡在掌握 -- kconfig 配置系統
kcon fi g是個強 大的工具 ,如果 說mak efil e制定了 完美的編 譯依賴關 系,那 麼kco nfi g制定了 完美的模 塊的依賴 關係 。
源頭
在根目錄 下有 個Kco nfi g文件, 這就是一 切故事的 起源 。
整個文件就沒幾行,打出來看一眼。
#
# For a description of the syntax of this configuration file,
# see Docu ment atio n/kb uild /kco nfig -lan guag e.tx t.
#
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
config SRCARCH
string
option env="SRCARCH"
# see Docu
#
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
config SRCARCH
string
option env="SRCARCH"
source "arc h/$S RCAR CH/K conf ig"
第一行就是輸出個內核版本號。
第二行應該是配置一個環境變量? 不知道,以後再來看。
第三行很 重要,這 個是包含 了一 個arc h目錄下 的Kco nfi g文件 。
當你打開
我們運行make menuconfig, 你可以看到,這個文件就是make menuconfig中顯示的東西。
一切都變 得明朗起 來,你是 否有種太 極生兩儀 ,兩儀生 四象,四 象生八卦 的神奇感 覺
剪不斷,理還亂
kern e l中這麼 多的模塊 之間的依 賴關係, 簡直就是 剪不斷,理還亂。
幸好 在Kco nfi g文件中 ,我們可 以找到一 點蛛絲馬 跡 。
依賴 depends on
這個關鍵 字表示了 在某些配 置選中後 ,本配置 項才會顯 示 。
在 driv er/p ci/K conf i g文件中 有 ,
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
depends on ARCH_SUPPORTS_MSI
可以發現 ,要配 置MS I必須要 先支 持PC I。 恩這個道理咱都懂, 連PCI都沒有,哪裡來的MSI啊。
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
depends on ARCH_SUPPORTS_MSI
可以發現
反向依賴 select
這個關鍵 字表示了 當本配置 項選中後 ,其他的 配置項也 需要選中 。
在 arch /x86 /Kco nfi g文件中 有 :
config HIGHMEM64G
bool "64GB"
depends on !M386 && !M486
select X86_PAE
---help---
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
其實這個 我也不懂 ,看上去 就是說要 支持更多 的物理內 存,那麼 在x8 6的平台 上,就要 選 中X86 _PA E。
bool "64GB"
depends on !M386 && !M486
select X86_PAE
---help---
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
其實這個
看上去是這麼回事兒。
革命尚未成功,同志仍需努力
好了,我 要記錄的 東西就到 這裡了。 突然這麼 嘎然而止 ,估計大 家一定意 猶未盡 。
但是事實 就是這樣 ,基本 的kco nfi g語法大 家可以在 Docu ment /kbu ild/ kcon fig- lang uage .tx t中找到 。
就不用我在這裡搬出來照抄了。
kern e l模塊之 間的關聯 又怎能是 我這樣的 初學者所 能理解, 不能理解 又豈能講 得清楚 。
這裡只是 給大家一 個入口, 讓大家能 夠進一步 的 在ker ne l的海洋 中探索。 話說,授 之以魚不 如授之以 漁嘛 。
要讓linux kern e l更好的 發揮作用 ,讓更多 的人參與 這個項目 ,幫助更 多的人, 還有很長 的路要走 。
革命尚未成功,同志仍需努力。