久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

也談Linux Kernel Hacking – Kconfig與Kbuild | Tony Bai

 蝸牛an 2015-06-10

也談Linux Kernel Hacking – Kconfig與Kbuild

三 18

bigwhite技術(shù)志 , , , , , , , , , , , , , , , , , , , , 6條評論

挖掘簡單現(xiàn)象背后的復(fù)雜本質(zhì),。– Tony Bai^_^

上文講到Linux Kernel的配置和編譯十分簡單,甚至簡單到可以與一個用戶層應(yīng)用相媲美,。這一切都是因為Linux Kernel實現(xiàn)了一套易于使用,、變更和后期維護的配置和編譯體系。要知道最新Linux Kernel版本的代碼量可是千萬級別的,,并且模塊眾多,,其背后的配置和編譯體系一定不那么簡單,這次我們就來嘗試Hack一下這套體系,。
作為操作系統(tǒng)內(nèi)核級系統(tǒng)軟件,,Linux Kernel在設(shè)計配置和編譯體系時至少應(yīng)該有如下幾點考慮:
* 滿足配置和編譯內(nèi)核以及內(nèi)核模塊的所有需求
* 較高的運行效率
* 配置階段和編譯階段平滑結(jié)合
* 對內(nèi)核開發(fā)者來說,這套體系應(yīng)該易用,、易變,、易維護
* 其設(shè)計本身應(yīng)該做到層次清晰
從配置和編譯Linux Kernel所使用的命令來看,Linux Kernel的配置和編譯體系總體上還是基于GNU Make的,,沒有另外使用其他的編譯工具(比如Scons,、CMake等),。但Linux Kernel實現(xiàn)了Kconfig和Kbuild,,用于輔助內(nèi)核的配置和編譯。
Kconfig,,顧名思義,,用于輔助2.6以后版本Linux內(nèi)核的配置(Kernel config);Kbuild,,也物如其名,,用于輔助2.6以后版本Linux內(nèi)核的編譯(Kernel build)。這里索性將Kconfig和Kbuild稱作輔助工具(不單純叫腳本或配置文件),,因為它們自身既有邏輯概念,,又有物理存在。如果你曾在Linux Kernel的源碼目錄中徜徉過,,你就會知道Kconfig文件散布在核心源碼的各個角落,;Kbuild文件還好,只在頂層目錄,、include目錄下子目錄,、drivers下子目錄以及各個arch/$ARCH/include的子目錄中分布。
如果Linux Kernel沒有引入Kconfig和Kbuild,,那么本篇文章就沒有了存在的必要性 – Makefile縱使數(shù)量眾多,,也是可以慢慢消化的,畢竟Make的規(guī)則就那么多,。但Kconfig和Kbuild的引入好似為Linux Kernel配置和編譯引入了一層抽象,,對外(Linux核心開發(fā)者)確實是簡單了,,但對于我這樣的要Hack編譯體系的人來說,這層抽象本身就具有一定復(fù)雜性,,勢必需要耗時耗力地去理解,。下面我們就來結(jié)合不同階段的使用場景來深入理解一下Kconfig和Kbuild。
一,、make *config階段
Linux Kernel的配置項都存儲于散布在Kernel源碼各處的Kconfig文件中,。Kconfig文件之于Linux Kernel就好比configure.ac或Makefile.am之于那些使用autotools作為構(gòu)建工具的用戶層應(yīng)用,至少設(shè)計思路是類似的 – 先config,,再make,;make階段會利用config階段生成的一些文件。
Kconfig既是配置文件,,也是一種配置語言,,可以理解為是一種針對Linux Kernel配置的領(lǐng)域特定語言(DSL)。Documentation/kbuild/kconfig-language.txt文件對該種配置語言做了詳盡的使用說明,,這里就不做贅述了,。我們主要關(guān)注的是Kconfig在配置過程中所扮演的角色以及對輸出的結(jié)果的影響。
Linux Kernel的配置過程也是在make的驅(qū)動下開始的,,我們以"make menuconfig"的執(zhí)行過程為例,。
1、首先,,頂層Makefile通過分析$(MAKECMDGOALS)判定"menuconfig"為config-targets,,而非build-target或mixed-target(諸如make defconfig all這樣的命令);
2,、"menuconfig"與Makefile中預(yù)置target進行匹配
menuconfig會匹配到Makefile中的"config %config",,下面是有關(guān)這個target的源碼節(jié)選:
include $(srctree)/scripts/Kbuild.include
… …
include $(srctree)/arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG KBUILD_KCONFIG
config %config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@
"config %config"有三個依賴項:scripts_basic、outputmakefile和FORCE,。其中outputmakefile,、FORCE是兩個空目標,而有關(guān)scripts_basic target的源碼如下:
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
    $(Q)$(MAKE) $(build)=scripts/basic
scripts_basic target的構(gòu)建實際上就是編譯scripts/basic下的源文件,。build變量在scritps/Kbuild.include中定義,,其值為"-f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj",所以上述命令展開后就是"make -f scripts/Makefile.build obj=scripts/basic",。scripts/Makefile.build這個文件在整個Linux Kernel編譯過程中占據(jù)極其重要的位置,,其定義了核心編譯的主要target(如.o、.s等)的構(gòu)建命令規(guī)則,。
3,、menuconfig目標的構(gòu)建
在依賴項scripts_basic構(gòu)建完畢后,Make驅(qū)動執(zhí)行menuconfig目標的構(gòu)建:
首先,創(chuàng)建兩個目錄include/linux和include/config,,然后執(zhí)行"make -f scripts/Makefile.build obj=scripts/kconfig menuconfig",。target依舊是"menuconfig",但scripts/Makefile.build中似乎并沒有這個target可供匹配啊,。別急,,我們看看scripts/Makefile.build中的這段代碼:
src := $(obj)
… …
# 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)
這是一段關(guān)鍵代碼,kbuild-dir的求值結(jié)果為scripts/kconfig,,由于scripts/kconfig下沒有Kbuild文件,,進而kbuild-file求值結(jié)果為scripts/kconfig/Makefile,并且該文件被Makefile.build包含了進來,。從kbuild-file這個變量的命名可以看出為何各個子目錄下的Makefile被稱為Kbuild Makefile了,。
scripts/kconfig/Makefile中包含了許多*config targets,其中就有"menuconfig"這個target:
ifdef KBUILD_KCONFIG
Kconfig := $(KBUILD_KCONFIG)
else
Kconfig := arch/$(SRCARCH)/Kconfig
endif
… …
menuconfig: $(obj)/mconf
    $< $(Kconfig)
該目標依賴scripts/kconfig/mconf,,這是一個小工具程序,,Make會首先執(zhí)行該程序的編譯鏈接;然后執(zhí)行"scripts/kconfig/mconf arch/x86/Kconfig"($<是一個自動變量,,指代該target的第一個依賴項,,這里是scripts/kconfig/mconf)。
4,、"scripts/kconfig/mconf arch/x86/Kconfig"的執(zhí)行過程
到這里,,Kconfig配置文件終于登場了!scripts/kconfig/mconf讀取arch/x86/Kconfig,,后者是一個針對x86這一體系的頂層Kconfig文件,,打開arch/x86/Kconfig后,你會發(fā)現(xiàn)它內(nèi)部source了許多其他Kconfig文件,,諸如:
….
source "init/Kconfig"
source "kernel/time/Kconfig"
source "mm/Kconfig"
mconf會依次讀入這些子Kconfig文件,并將配置項的符號表建立起來,。如果你是第一次進行Linux Kernel配置,,尚沒有.config文件,那么這些配置項的初始值從哪里得到呢(不是所有配置項都有默認值),?在init/Kconfig文件中,,你會看到這樣的配置項:
config DEFCONFIG_LIST
    string
    depends on !UML
    option defconfig_list
    default "/lib/modules/$UNAME_RELEASE/.config"
    default "/etc/kernel-config"
    default "/boot/config-$UNAME_RELEASE"
    default "$ARCH_DEFCONFIG"
    default "arch/$ARCH/defconfig"
mconf應(yīng)該就是通過這個DEFCONFIG_LIST配置項找到一份默認config文件的,mconf自上而下依次嘗試,,直到對應(yīng)的文件存在,,就將存在的文件作為默認.config加載,為各個配置項賦值,。在我的RHEL 5.5上$ARCH-DEFCONFIG被作為默認.config加載了,;而在我的Ubuntu 10.04上,mconf找到的是/boot/config-2.6.32-30-generic。下面是在RHEL 5.5上執(zhí)行make menuconfig后控制臺的輸出結(jié)果:
$ make menuconfig
scripts/kconfig/mconf arch/x86/Kconfig
#
# using defaults found in arch/x86/configs/x86_64_defconfig
#
#
# configuration written to .config
#
*** End of Linux kernel configuration.
5,、生成.config文件
手工完成配置后,,如果選擇了save配置,那么在源碼頂層目錄下會生成一個.config文件,,這個就是整個Kernel配置過程的最重要的輸出,,這類似用戶層應(yīng)用在configure之后生成的Makefile,.config文件實際上也是一個Makefile文件,,只是其內(nèi)容格式比較單一罷了(都是CONFIG_XXX=y形式的變量定義),。
至此,Linux Kernel的配置過程Hack結(jié)束了,,其他*config target執(zhí)行過程也是大同小異的,,再總結(jié)一下make menuconfig配置的執(zhí)行過程:
* 首先建立include/config目錄,并編譯scripts/basic下的一些工具,;
* 然后編譯scripts/kconfig下的工具,,比如mconf等
* 執(zhí)行scripts/kconfig/mconf arch/x86/Kconfig,該程序會生成.config
二,、make all階段
Make *config后,,Kconfig文件的使命就算是結(jié)束了。剩下的Makefile和Kbuild文件將會在make all階段扮演重要角色,。前面說過Kbuild本身就是Makefile,,分布在各個子目錄中Makefile也被稱為Kbuild Makefile,其實還是Makefile,總而言之,,Make all階段其實就是關(guān)于Makefile的事情了,。只不過Linux Kernel的整個Makefile組織體系設(shè)計的很精巧,特別是與配置階段輸出的結(jié)果配合的天衣無縫,,下面我們就來具體看看吧,。
在頂層的Makefile中,我們可以直接定位到Make all的target,,不過有兩個,,依次是:
all: vmlinux
all: modules
Make會自動合并all的依賴項,并依次對依賴項進行構(gòu)建,,就類似這樣:
all: foo1
all: foo2
foo1:
        @echo "foo1"
foo2:
        @echo "foo2"
$> make
foo1
foo2
而vmlinux這個target是什么情況呢,?見下面代碼摘要:
# vmlinux image – including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
… …
    $(call vmlinux-modpost)
    $(call if_changed_rule,vmlinux__)
    $(Q)rm -f .old_version
… … 
# The actual objects are generated when descending, 
# make sure no implicit rule kicks in
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
從代碼中可以看到vmlinux有若干個依賴項,我們沿著這些依賴項繼續(xù)"深度"搜索,,你會發(fā)現(xiàn)這是一個"不算淺"的依賴項樹型結(jié)構(gòu),,樹的根節(jié)點就是vmlinux。由于這棵樹太過"枝繁葉茂",,所以這里只想針對重要且關(guān)鍵的依賴項進行分析,。
1,、prepare
這個phony target是$(vmlinux-dirs)的依賴項,顧名思義,,在真正地編譯之前做些準備工作,。目前所有的準備工作被劃分到從prepare0到prepare3的多個phony targets中了,形成一個鏈式依賴關(guān)系,,這么做也便于日后擴展:再增加一個prepare-n非常容易,。
在prepare的過程中有若干的重要的文件被生成了:
include/linux/version.h: $(srctree)/Makefile FORCE
    $(call filechk,version.h)
include/linux/utsrelease.h: include/config/kernel.release FORCE
    $(call filechk,utsrelease.h)
include/config/kernel.release: include/config/auto.conf FORCE
    $(Q)rm -f $@
    $(Q)echo $(kernelrelease) > $@
include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
    $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
其中include/config/auto.conf依賴$(KCONFIG_CONFIG)和include/config/auto.conf.cmd,頂層Makefile中設(shè)置了auto.conf.cmd這個target的空規(guī)則:
# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
這樣實際上include/config/auto.conf在auto.conf.cmd尚未被創(chuàng)建的情況下只是依賴配置階段輸出的.config文件(KCONFIG_CONFIG  ?= .config),。而Kernel配置后,,auto.conf也未被創(chuàng)建,因此在這里Make執(zhí)行創(chuàng)建auto.conf的命令:make -f Makefile silentoldconfig,,該命令的執(zhí)行結(jié)果是auto.conf,、auto.conf.cmd、include/linux/autoconf.h以及include/config下的諸多空頭文件被創(chuàng)建了出來,。
2,、$(vmlinux-dirs)
$(vmlinux-dirs)是一個非常重要的target,$(vmlinux-init),、$(vmlinux-main),、$(vmlinux-lds)都依賴$(vmlinux-dirs)。
init-y      := init/
drivers-y   := drivers/ sound/ firmware/
net-y       := net/
libs-y      := lib/
core-y      := usr/
… …
core-y      += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))
PHONY += $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
此時vmlinux-dirs的值是一組目錄集合,,諸如init usr kernel mm fs ipc security crypto block drivers sound firmware net lib等,。Makefile將這些目錄名視為phony target。這樣$(vmlinux-dirs): prepare scripts這個規(guī)則實際上就是一個multiple targets規(guī)則,,會被多次執(zhí)行的,,即會對每個target執(zhí)行一次"$(Q)$(MAKE) $(build)=$@"。我們以init這個phony target為例展開命令:make -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build
obj=init,,該命令將根據(jù)Makefile.build中定義的規(guī)則對init目錄進行編譯,。Makefile.build規(guī)則中的默認phony target為__build:
PHONY := __build
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
    @:
__build"復(fù)雜"的依賴項會將必要的目標包含進來,其中較關(guān)鍵的是builtin-target這個目標:
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
#
# Rule to compile a set of .o files into one .o file
#
ifdef builtin-target
quiet_cmd_link_o_target = 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), $^) \
              $(cmd_secanalysis),\
              rm -f $@; $(AR) rcs $@)
$(builtin-target): $(obj-y) FORCE
    $(call if_changed,link_o_target)
targets += $(builtin-target)
endif # builtin-target
這樣每個子目錄(諸如mm,、init等)下的主要目標就是built-in.o,,其依賴的是$(obj-y),展開后其實是一個.o文件列表,。
這里還要提一點,那就是配置階段的輸出是如何與Build階段結(jié)合的,,我們還是看一下init/Makefile,,這里節(jié)選一些代碼:
obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
mounts-$(CONFIG_BLK_DEV_RAM)    += do_mounts_rd.o
mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o
mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o
可以看到.config中的配置項的值將各個.o文件分為幾個類別,如果配置項值為y,,則對應(yīng)的.o文件歸為obj-y列表,;如果為m,則對應(yīng)的.o文件歸為obj-m列表,諸如此類(包括lib-y,、lib-m,、subdir-y、subdir-m等),。這樣我們就可以通過調(diào)整配置項的值來選擇是否將某功能編譯到Linux Kernel中,,還是以Kernel module形式存在,讓人嘆為觀止,!
3,、$(vmlinux-lds)
在頂層Makefile源碼中vmlinux-lds  := arch/$(SRCARCH)/kernel/vmlinux.lds,vmlinux.lds是vmlinux的linker script,。vmlinux.lds也是在構(gòu)建$(vmlinux-dirs)目標時被構(gòu)建出來的,。
$(vmlinux-dirs)中包含arch/x86,而在arch/x86/Makefile中,,我們發(fā)現(xiàn)了這行代碼:
core-y += arch/x86/kernel/
這樣arch/x86/kernel被納入編譯,,而vmlinux.lds就是arch/x86/kernel/Makefile中變量extra-y的一個值:
extra-y                := head_$(BITS).o head$(BITS).o head.o init_task.o vmlinux.lds
vmlinux.lds會被構(gòu)建,而.lds目標構(gòu)建規(guī)則在scripts/Makefile.build中:
# Linker scripts preprocessor (.lds.S -> .lds)
# —————————————————————————
quiet_cmd_cpp_lds_S = LDS     $@
      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
$(obj)/%.lds: $(src)/%.lds.S FORCE
    $(call if_changed_dep,cpp_lds_S)
OK,,vmlinux.lds的來龍去脈也算是搞清楚了,。
4、其他
vmlinux的依賴還包括vmlinux-init,、vmlinux-main以及vmlinux.o,,見下面頂層Makefile的節(jié)選代碼:
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
    $(call if_changed_rule,vmlinux-modpost)
有了vmlinux-dirs那節(jié)的說明,這些依賴項的構(gòu)建也是大同小異的,。
當vmlinux的所有依賴項都構(gòu)建完畢后,,vmlinux的創(chuàng)建也就水到渠成了,這里就不多說了,。
總而言之,,Linux Kernel簡單配置和編譯的背后其實還是蠻復(fù)雜的,如果要挖掘細節(jié),,即使有了上面的Hack,,也還是會耗費你一定時間的^_^。

 

2012, bigwhite. 版權(quán)所有.

Related posts:

  1. 也談Linux Kernel Hacking – 內(nèi)核配置,、編譯與安裝
  2. 也談C應(yīng)用安裝包制作與部署
  3. 關(guān)于Makefile.am中與Build相關(guān)的變量設(shè)置
  4. Kernel 'head.S'
  5. Hello,,autoconf和automake

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多