新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Arm Linux Kernel 構建 情景分析

        Arm Linux Kernel 構建 情景分析

        作者: 時間:2016-11-09 來源:網絡 收藏

        概述

        構建一個內核,一般是先配置,后編譯。這里以構建 Nexus5 內核為例,代號為hammerhead。

        配置

        通常做法是以廠商預置的配置為基礎,根據自己需要進行配置。命令:
        make ARCH=arm hammerhead_defconfig

        本文引用地址:http://www.104case.com/article/201611/317990.htm
        執行完畢后,"arch/arm/configs/hammerhead_defconfig" 文件會被到 ".config" ,作為默認配置。
        然后運行以下命令根據自己需要進行配置:
        make ARCH=arm menuconfig

        編譯

        通常,需要生成 zImage 和 內核模塊。如果不指定目標,這兩個都會默認生成。命令:
        1. # CROSS_COMPILE 的值根據自己情況設定
          make ARCH=arm CROSS_COMPILE=arm-linux-androideabi-

        這條命令做了什么呢,把 make 輸出到控制臺的信息貼出來(省略中間相似的信息):
        make ARCH=arm CROSS_COMPILE=arm-linux-androideabi- CONFIG_DEBUG_SECTION_MISMATCH=yscripts/kconfig/conf --silentoldconfig KconfigWRAP arch/arm/include/generated/asm/auxvec.hWRAP arch/arm/include/generated/asm/bitsperlong.hWRAP arch/arm/include/generated/asm/cputime.h...WRAP arch/arm/include/generated/asm/siginfo.hWRAP arch/arm/include/generated/asm/sizes.hCHK include/linux/version.hUPD include/linux/version.hCHK include/generated/utsrelease.hUPD include/generated/utsrelease.hGenerating include/generated/mach-types.hCC kernel/bounds.sGEN include/generated/bounds.hCC arch/arm/kernel/asm-offsets.sGEN include/generated/asm-offsets.hCALL scripts/checksyscalls.shHOSTCC scripts/dtc/checks.oHOSTCC scripts/dtc/data.o...HOSTCC scripts/conmakehashHOSTCC scripts/recordmcountCC init/main.oCHK include/generated/compile.hUPD include/generated/compile.hCC init/version.oCC init/do_mounts.oCC init/do_mounts_rd.oCC init/do_mounts_initrd.oLD init/mounts.oCC init/initramfs.oCC init/calibrate.oLD init/built-in.o...AR lib/lib.aLD vmlinux.oMODPOST vmlinux.oGEN .versionCHK include/generated/compile.hUPD include/generated/compile.hCC init/version.oLD init/built-in.oLD .tmp_vmlinux1KSYM .tmp_kallsyms1.SAS .tmp_kallsyms1.oLD .tmp_vmlinux2KSYM .tmp_kallsyms2.SAS .tmp_kallsyms2.oLD vmlinuxSYSMAP System.mapSYSMAP .tmp_System.mapOBJCOPY arch/arm/boot/ImageKernel: arch/arm/boot/Image is readyAS arch/arm/boot/compressed/head.oGZIP arch/arm/boot/compressed/piggy.gzipAS arch/arm/boot/compressed/piggy.gzip.oCC arch/arm/boot/compressed/misc.oCC arch/arm/boot/compressed/decompress.oCC arch/arm/boot/compressed/string.oAS arch/arm/boot/compressed/lib1funcs.oAS arch/arm/boot/compressed/ashldi3.oLD arch/arm/boot/compressed/vmlinuxOBJCOPY arch/arm/boot/zImageKernel: arch/arm/boot/zImage is readyDTC arch/arm/boot/msm8974-hammerhead-rev-11.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-11j.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-10.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-c.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-b.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-bn.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-a.dtbDTC arch/arm/boot/msm8974-hammerhead-rev-f.dtbCAT arch/arm/boot/zImage-dtbKernel: arch/arm/boot/zImage-dtb is readymake[1]:沒有什么可以做的為`arch/arm/boot/dtbs。

        簡單分析一下,大致做了這么幾件事情:
        1. 根據配置信息,生成了一些頭文件
        2. 編譯了一些小工具
        3. 根據配置信息,有選擇性地編譯一些源碼,將輸出的 obj 鏈接成對應的 built-in.o
        4. 生成符號表文件
        5. 將所有的 built-in.o 和符號表鏈接成內核 vmlinux
        6. 使用 BOJCOPY 從 vmlinux 生成 Image
        7. 生成壓縮過的內核 arch/arm/boot/compressed/vmlinux
        8. 使用 OBJCOPY 從 壓縮過的內核 vmlinux 生成 zImage
        9. 生成 dtb(device tree blob)
        10. 將 zImage 和 dtb 連接成一個文件:zImage-dtb
        而我們最終需要的文件就是 zImage-dtb(注意:這里沒有生成內核模塊,因為所有的內核功能都被配置為 built-in ,編譯進 zImage-dtb 了)。

        要點分析

        內核配置和編譯,依靠的是 make 和 kbuild 系統。無論是 make 還是 kbuild,都只是工具,我們并不一定要完全弄清其內部工作原理,只需要熟悉和工作相關的部分即可。
        這里涉及到的有如下幾點:
        • vmlinux 的構建過程
        • arch/arm/boot/compressed/vmlinux 的構建過程
        • 源碼是如何選擇性地參與內核的構建的
        之所以要分析 vmlinux 和 arch/arm/boot/compressed/vmlinux ,是因為這個兩個文件是最原始的兩個可執行文件:Image 由 vmlinux 生成;zImage 由 arch/arm/boot/compressed/vmlinux 生成。分析這連個文件的生成,還有助于分析 linux 內核的啟動過程。

        基礎

        vmlinux 是 makefile 中的一個目標。makefile 中的規則定義了目標和源碼的關系,命令則定義了如何由源碼生成目標,變量起輔助作用。規則、命令和變量是 makefile 的三大要素。理清 makefile 規則中定義的依賴關系是分析構建過程的關鍵。涉及到的幾個重要文件:
        Makefilearch/arm/Makefilearch/arm/boot/Makefilearch/arm/mach-msm/Makefile.bootarch/arm/compressed/Makefile


        vmlinux 是一個可執行程序,其鏈接過程必然涉及的鏈接腳本,鏈接腳本是做什么的?看看 ld 手冊中的描述:
        通過 lds 文件,我們至少可以知道一個可執行程序的入口在哪里。
        這里又要涉及到幾個重要文件:
        # 對應 vmlinuxarch/arm/kernel/vmlinux.lds# 對應 /arch/arm/boot/compressed/vmlinuxarch/arm/boot/compressed/vmlinux.lds

        vmlinux 是一個可執行程序,由源碼編譯、鏈接而來。那么是哪些源碼參與了構建過程,又是如何控制這些源碼參與的?后面會分析。
        為了分析 makefile,這里借用了 UML 的概念。
        用 包 表示 makefile 文件;用 類 表示 目標和文件;用類間依賴表示目標的依賴;用組合表示變量的定義。
        下面是一個總圖,表明了各個目標之間的依賴關系:
        (紅色邊框是可執行程序,藍色邊框是對應的鏈接腳本)
        vmlinux 的構建過程

        和 lds 文件的關系

        ?依賴鏈:
        _all->all->vmlinux->$(vmlinux-lds)=arch/arm/kernel/vmlinux.lds

        從 _all 到 all:

        PHONY += allifeq ($(KBUILD_EXTMOD),)_all: allelse_all: modulesendif

        KBUILD_EXTMOD 只有在內核樹外編譯內核模塊的時候才會定義 M 變量,從而給其賦值,否則為空,這里為空。

        從 all 到 vmlinux:
        all: vmlinux

        從 vmlinux 到 $(vmlinux-lds):
        vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE

        $(vmlinux-lds) 定義:
        vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds

        和源碼的關系

        ?依賴鏈:
        _all->all->vmlinux->$(vmlinux-init)+$(vmlinux-main)

        看看這個:
        # vmlinux# ^# # +-< $(vmlinux-init)#  +--< init/version.o + more# # +--< $(vmlinux-main)#  +--< driver/built-in.o mm/built-in.o + more# # +-< kallsyms.o (see description in CONFIG_KALLSYMS section)

        關鍵部分上面已經列出,這里再次列出來:
        vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE

        那么 $(vmlinux-init) 連個變量是什么呢?通過分析,第一次展開后為:“$(head-y) $(init-y)”。沒有找到 $(head-y),而 $(init-y) 最終展開為:init/built-in.o。
        到這里有點眉目了(回頭看看 make 過程輸出的信息,里面有大量的 built-in.o)。可以說是眾多的 built-in.o構成了vmlinux。所以 vmlinux 和源碼的關系轉變成了 built-in.o 和源碼的關系。
        還是看 make 的輸出信息:
        CC init/version.oCC init/do_mounts.oCC init/do_mounts_rd.oCC init/do_mounts_initrd.oLD init/mounts.oCC init/initramfs.oCC init/calibrate.oLD init/built-in.o

        可以推測:init/built-in.o 是由 init 目錄下的 源碼編譯、鏈接而成。在 init 目錄下發現 Makefile:
        obj-y := main.o version.o mounts.oifneq ($(CONFIG_BLK_DEV_INITRD),y)obj-y += noinitramfs.oelseobj-$(CONFIG_BLK_DEV_INITRD)+= initramfs.oendifobj-$(CONFIG_GENERIC_CALIBRATE_DELAY)+= calibrate.omounts-y := do_mounts.omounts-$(CONFIG_BLK_DEV_RAM)+= do_mounts_rd.omounts-$(CONFIG_BLK_DEV_INITRD)+= do_mounts_initrd.omounts-$(CONFIG_BLK_DEV_MD)+= do_mounts_md.o

        有內核開發經驗的開發者應該知道,賦值到 obj-y 的目標會被編譯進 vmlinux,至于是如何控制的,推測 kbuild 系統是有參與的,這屬于 make 和 kubild 的內部原理,這里不分析了,知道有這么回事,會用就行了。$(CONFIG_BLK_DEV_INITRD) 等變量在 .config(沒錯,就是保存內核配置的文件) 文件中定義:
        CONFIG_RELAY=yCONFIG_BLK_DEV_INITRD=yCONFIG_INITRAMFS_SOURCE=""

        這里 vmlinux 和源碼的關系就搞清了,是由 built-in.o 來當中間人的:
        vmlinux<->built-in.o<->*.c

        和符號表的關系

        略。

        arch/arm/boot/comressed/vmlinux 的構建過程

        有了分析 vmlinux 的基礎,分析壓縮過的 vmlinux 就容易了。看 規則:
        $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE@$(check_for_multiple_zreladdr)$(call if_changed,ld)@$(check_for_bad_syms)

        參與壓縮過的 vmlinux 的構建過程的主要有三類文件:
        • 鏈接腳本:arch/arm/boot/compressed/vmlinux.lds
        • 解壓代碼:arch/arm/boot/compressed/ 下的源碼
        • 壓縮的數據:壓縮的 Image(由未經壓縮的 vmlinux 生成)
        因為解壓縮功能和內核開發關系不大,就不具體分析了。


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 修水县| 沂源县| 平昌县| 沁源县| 青州市| 德令哈市| 米易县| 晋中市| 佛冈县| 怀柔区| 武陟县| 北流市| 浦城县| 祁东县| 崇文区| 翼城县| 肃宁县| 承德市| 抚顺县| 四子王旗| 江源县| 景宁| 吐鲁番市| 绥德县| 富平县| 龙陵县| 团风县| 左云县| 留坝县| 嵊泗县| 万全县| 连平县| 岳普湖县| 社会| 松滋市| 珠海市| 曲麻莱县| 武邑县| 涟水县| 东安县| 洛扎县|