概述
建構一個核心,一般是先配置,後編譯。這裡以建構 Nexus5 核心為例,代号為 hammerhead。配置
通常做法是以廠商預置的配置為基礎,根據自己需要進行配置。指令:執行完畢後,"arch/arm/configs/hammerhead_defconfig" 檔案會被複制到 ".config" ,作為預設配置。 然後運作以下指令根據自己需要進行配置:make ARCH=arm hammerhead_defconfig
make ARCH=arm menuconfig
編譯
通常,需要生成 zImage 和 核心子產品。如果不指定目标,這兩個都會預設生成。指令:這條指令做了什麼呢,把 make 輸出到控制台的資訊貼出來(省略中間相似的資訊):
# CROSS_COMPILE 的值根據自己情況設定
make ARCH=arm CROSS_COMPILE=arm-linux-androideabi-
簡單分析一下,大緻做了這麼幾件事情:make ARCH=arm CROSS_COMPILE=arm-linux-androideabi- CONFIG_DEBUG_SECTION_MISMATCH=y scripts/kconfig/conf --silentoldconfig Kconfig WRAP arch/arm/include/generated/asm/auxvec.h WRAP arch/arm/include/generated/asm/bitsperlong.h WRAP arch/arm/include/generated/asm/cputime.h ... WRAP arch/arm/include/generated/asm/siginfo.h WRAP arch/arm/include/generated/asm/sizes.h CHK include/linux/version.h UPD include/linux/version.h CHK include/generated/utsrelease.h UPD include/generated/utsrelease.h Generating include/generated/mach-types.h CC kernel/bounds.s GEN include/generated/bounds.h CC arch/arm/kernel/asm-offsets.s GEN include/generated/asm-offsets.h CALL scripts/checksyscalls.sh HOSTCC scripts/dtc/checks.o HOSTCC scripts/dtc/data.o ... HOSTCC scripts/conmakehash HOSTCC scripts/recordmcount CC init/main.o CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o CC init/do_mounts.o CC init/do_mounts_rd.o CC init/do_mounts_initrd.o LD init/mounts.o CC init/initramfs.o CC init/calibrate.o LD init/built-in.o ... AR lib/lib.a LD vmlinux.o MODPOST vmlinux.o GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o LD init/built-in.o LD .tmp_vmlinux1 KSYM .tmp_kallsyms1.S AS .tmp_kallsyms1.o LD .tmp_vmlinux2 KSYM .tmp_kallsyms2.S AS .tmp_kallsyms2.o LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready AS arch/arm/boot/compressed/head.o GZIP arch/arm/boot/compressed/piggy.gzip AS arch/arm/boot/compressed/piggy.gzip.o CC arch/arm/boot/compressed/misc.o CC arch/arm/boot/compressed/decompress.o CC arch/arm/boot/compressed/string.o AS arch/arm/boot/compressed/lib1funcs.o AS arch/arm/boot/compressed/ashldi3.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready DTC arch/arm/boot/msm8974-hammerhead-rev-11.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-11j.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-10.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-c.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-b.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-bn.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-a.dtb DTC arch/arm/boot/msm8974-hammerhead-rev-f.dtb CAT arch/arm/boot/zImage-dtb Kernel: arch/arm/boot/zImage-dtb is ready make[1]:沒有什麼可以做的為`arch/arm/boot/dtbs'。
而我們最終需要的檔案就是 zImage-dtb(注意:這裡沒有生成核心子產品,因為所有的核心功能都被配置為 built-in ,編譯進 zImage-dtb 了)。
- 根據配置資訊,生成了一些頭檔案
- 編譯了一些小工具
- 根據配置資訊,有選擇性地編譯一些源碼,将輸出的 obj 連結成對應的 built-in.o
- 生成符号表檔案
- 将所有的 built-in.o 和符号表連結成核心 vmlinux
- 使用 BOJCOPY 從 vmlinux 生成 Image
- 生成壓縮過的核心 arch/arm/boot/compressed/vmlinux
- 使用 OBJCOPY 從 壓縮過的核心 vmlinux 生成 zImage
- 生成 dtb(device tree blob)
- 将 zImage 和 dtb 連接配接成一個檔案:zImage-dtb
要點分析
核心配置和編譯,依靠的是 make 和 kbuild 系統。無論是 make 還是 kbuild,都隻是工具,我們并不一定要完全弄清其内部工作原理,隻需要熟悉和工作相關的部分即可。 這裡涉及到的有如下幾點:之是以要分析 vmlinux 和 arch/arm/boot/compressed/vmlinux ,是因為這個兩個檔案是最原始的兩個可執行檔案:Image 由 vmlinux 生成;zImage 由 arch/arm/boot/compressed/vmlinux 生成。分析這連個檔案的生成,還有助于分析 linux 核心的啟動過程。
- vmlinux 的建構過程
- arch/arm/boot/compressed/vmlinux 的建構過程
- 源碼是如何選擇性地參與核心的建構的
基礎
vmlinux 是 makefile 中的一個目标。makefile 中的規則定義了目标和源碼的關系,指令則定義了如何由源碼生成目标,變量起輔助作用。規則、指令和變量是 makefile 的三大要素。 理清 makefile 規則中定義的依賴關系是分析建構過程的關鍵。涉及到的幾個重要檔案:vmlinux 的建構過程vmlinux 是一個可執行程式,其連結過程必然涉及的連結腳本,連結腳本是做什麼的?看看 ld 手冊中的描述: 通過 lds 檔案,我們至少可以知道一個可執行程式的入口在哪裡。 這裡又要涉及到幾個重要檔案:Makefile arch/arm/Makefile arch/arm/boot/Makefile arch/arm/mach-msm/Makefile.boot arch/arm/compressed/Makefile
vmlinux 是一個可執行程式,由源碼編譯、連結而來。那麼是哪些源碼參與了建構過程,又是如何控制這些源碼參與的?後面會分析。 為了分析 makefile,這裡借用了 UML 的概念。 用 包 表示 makefile 檔案;用 類 表示 目标和檔案;用類間依賴表示目标的依賴;用組合表示變量的定義。 下面是一個總圖,表明了各個目标之間的依賴關系: (紅色邊框是可執行程式,藍色邊框是對應的連結腳本)# 對應 vmlinux arch/arm/kernel/vmlinux.lds # 對應 /arch/arm/boot/compressed/vmlinux arch/arm/boot/compressed/vmlinux.lds
和 lds 檔案的關系
依賴鍊:從 _all 到 all:_all->all->vmlinux->$(vmlinux-lds)=arch/arm/kernel/vmlinux.lds
PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endif
KBUILD_EXTMOD 隻有在核心樹外編譯核心子產品的時候才會定義 M 變量,進而給其指派,否則為空,這裡為空。
從 all 到 vmlinux:
從 vmlinux 到 $(vmlinux-lds):all: vmlinux
$(vmlinux-lds) 定義:vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
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-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 的輸出資訊:vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
可以推測:init/built-in.o 是由 init 目錄下的 源碼編譯、連結而成。在 init 目錄下發現 Makefile:CC init/version.o CC init/do_mounts.o CC init/do_mounts_rd.o CC init/do_mounts_initrd.o LD init/mounts.o CC init/initramfs.o CC init/calibrate.o LD init/built-in.o
有核心開發經驗的開發者應該知道,指派到 obj-y 的目标會被編譯進 vmlinux,至于是如何控制的,推測 kbuild 系統是有參與的,這屬于 make 和 kubild 的内部原理,這裡不分析了,知道有這麼回事,會用就行了。$(CONFIG_BLK_DEV_INITRD) 等變量在 .config(沒錯,就是儲存核心配置的檔案) 檔案中定義:obj-y := main.o version.o mounts.o ifneq ($(CONFIG_BLK_DEV_INITRD),y) obj-y += noinitramfs.o else obj-$(CONFIG_BLK_DEV_INITRD)+= initramfs.o endif obj-$(CONFIG_GENERIC_CALIBRATE_DELAY)+= calibrate.o mounts-y := do_mounts.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
這裡 vmlinux 和源碼的關系就搞清了,是由 built-in.o 來當中間人的:CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE=""
vmlinux<->built-in.o<->*.c
和符号表的關系
略。
arch/arm/boot/comressed/vmlinux 的建構過程
有了分析 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)
因為解壓縮功能和核心開發關系不大,就不具體分析了。
- 連結腳本:arch/arm/boot/compressed/vmlinux.lds
- 解壓代碼:arch/arm/boot/compressed/ 下的源碼
- 壓縮的資料:壓縮的 Image(由未經壓縮的 vmlinux 生成)
轉載于:https://www.cnblogs.com/JonnyLulu/p/4214020.html