您的位置 首页 硬件

Arm Linux Kernel 构建 情形剖析

概述构建一个内核,一般是先配置,后编译。这里以构建Nexus5内核为例,代号为hammerhead。配置通常做法是以厂商预置的配置为基础,根据…

概述

构建一个内核,一般是先装备,后编译。这儿以构建 Nexus5 内核为例,代号为hammerhead。

装备

一般做法是以厂商预置的装备为根底,依据自己需求进行装备。指令:

make ARCH=arm hammerhead_defconfig
履行结束后,”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 生成)

由于解紧缩功用和内核开发联系不大,就不具体剖析了。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/yingjian/277327.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部