设为首页 加入收藏

TOP

你知道 Linux 内核是如何构建的吗?(二)
2015-11-10 13:46:12 来源: 作者: 【 】 浏览:21
Tags:知道 Linux 内核 如何 构建
,目标 all 依赖于根 makefile 后面声明的 vmlinux


vmlinux 是 linux 内核的静态链接可执行文件格式。脚本 scripts/link-vmlinux.sh 把不同的编译好的子模块链接到一起形成了 vmlinux。


第二个目标是 vmlinux-deps,它的定义如下:


它是由内核代码下的每个顶级目录的 built-in.o 组成的。之后我们还会检查内核所有的目录,kbuild 会编译各个目录下所有的对应 $(obj-y) 的源文件。接着调用 $(LD) -r 把这些文件合并到一个 build-in.o 文件里。此时我们还没有vmlinux-deps,所以目标 vmlinux 现在还不会被构建。对我而言 vmlinux-deps 包含下面的文件:


下一个可以被执行的目标如下:


就像我们看到的,vmlinux-dir 依赖于两部分:preparescripts。第一个 prepare 定义在内核的根 makefile 中,准备工作分成三个阶段:


第一个 prepare0 展开到 archprepare ,后者又展开到 archheaderarchscripts,这两个变量定义在 x86_64 相关的 Makefile。让我们看看这个文件。x86_64 特定的 makefile 从变量定义开始,这些变量都是和特定架构的配置文件 (defconfig,等等)有关联。在定义了编译 16-bit 代码的编译选项之后,根据变量 BITS 的值,如果是 32, 汇编代码、链接器、以及其它很多东西(全部的定义都可以在arch/x86/Makefile找到)对应的参数就是 i386,而 64 就对应的是 x86_84


第一个目标是 makefile 生成的系统调用列表(syscall table)中的 archheaders


第二个目标是 makefile 里的 archscripts


我们可以看到 archscripts 是依赖于根 Makefile里的scripts_basic 。首先我们可以看出 scripts_basic 是按照 scripts/basic 的 makefile 执行 make 的:


scripts/basic/Makefile 包含了编译两个主机程序 fixdepbin2 的目标:


第一个工具是 fixdep:用来优化 gcc 生成的依赖列表,然后在重新编译源文件的时候告诉make。第二个工具是 bin2c,它依赖于内核配置选项 CONFIG_BUILD_BIN2C,并且它是一个用来将标准输入接口(LCTT 译注:即 stdin)收到的二进制流通过标准输出接口(即:stdout)转换成 C 头文件的非常小的 C 程序。你可能注意到这里有些奇怪的标志,如 hostprogs-y 等。这个标志用于所有的 kbuild 文件,更多的信息你可以从documentation 获得。在我们这里, hostprogs-y 告诉 kbuild 这里有个名为 fixed 的程序,这个程序会通过和 Makefile 相同目录的 fixdep.c 编译而来。


执行 make 之后,终端的第一个输出就是 kbuild 的结果:


当目标 script_basic 被执行,目标 archscripts 就会 make arch/x86/tools 下的 makefile 和目标 relocs:


包含了重定位 的信息的代码 relocs_32.crelocs_64.c 将会被编译,这可以在make 的输出中看到:


在编译完 relocs.c 之后会检查 version.h:


我们可以在输出看到它:


以及在内核的根 Makefiel 使用 arch/x86/include/generated/asm 的目标 asm-generic 来构建 generic 汇编头文件。在目标 asm-generic 之后,archprepare 就完成了,所以目标 prepare0 会接着被执行,如我上面所写:


注意 build,它是定义在文件 scripts/Kbuild.include,内容是这样的:


或者在我们的例子中,它就是当前源码目录路径:.


脚本 scripts/Makefile.build 通过参数 obj 给定的目录找到 Kbuild 文件,然后引入 kbuild 文件:


并根据这个构建目标。我们这里 . 包含了生成 kernel/bounds.sarch/x86/kernel/asm-offsets.sKbuild 文件。在此之后,目标 prepare 就完成了它的工作。 vmlinux-dirs 也依赖于第二个目标 scripts ,它会编译接下来的几个程序:filealiasmk_elfconfigmodpost 等等。之后,scripts/host-programs 就可以开始编译我们的目标 vmlinux-dirs 了。


首先,我们先来理解一下 vmlinux-dirs 都包含了那些东西。在我们的例子中它包含了下列内核目录的路径:


我们可以在内核的根 Makefile 里找到 vmlinux-dirs 的定义:


这里我们借助函数 patsubstfilter去掉了每个目录路径里的符号 /,并且把结果放到 vmlinux-dirs 里。所以我们就有了 vmlinux-dirs 里的目录列表,以及下面的代码:


符号 $@ 在这里代表了 vmlinux-dirs,这就表明程序会递归遍历从 vmlinux-dirs 以及它内部的全部目录(依赖于配置),并且在对应的目录下执行 make 命令。我们可以在输出看到结果:


每个目录下的源代码将会被编译并且链接到 built-io.o 里:


好了,所有的 built-in.o 都构建完了,现在我们回到目标 vmlinux 上。你应该还记得,目标 vmlinux 是在内核的根makefile 里。在链接 vmlinux 之前,系统会构建 samples, Documentation 等等,但是如上文所述,我不会在本文描述这些。


你可以看到,调用脚本 scripts/link-vmlinux.sh 的主要目的是把所有的 built-in.o 链接成一个静态可执行文件,和生成 System.map。 最后我们来看看下面的输出:


vmlinuxSystem.map 生成在内核源码树根目录下。


这就是全部了,vmlinux 构建好了,下一步就是创建 bzImage.


?


bzImage 就是压缩了的 linux 内核镜像。我们可以在构建了 vmlinux 之后通过执行 make bzImage 获得bzImage。同时我们可以仅仅执行 make 而不带任何参数也可以生成 bzImage ,因为它是在 arch/x86/kernel/Makefile 里预定义的、默认生成的镜像:


让我们看看这个目标,它能帮助我们理解这个镜像是怎么构建的。我已经说过了 bzImage 是被定义在 arch/x86/kernel/Makefile,定义如下:


在这里我们可以看到第一次为 boot 目录执行 make,在我们的例子里是这样的:


现在的主要目标是编译目录 arch/x86/bootarch/x86/boot/compressed 的代码,构建 setup.binvmlinux.bin,最后用这两个文件生成 bzImage。第一个目标是定义在 arch/x86/boot/Makefile$(obj)/setup.elf:


我们已经在目录 arch/x86/boot 有了链接脚本 setup.ld,和扩展到 boot 目录下全部源代码的变量 SETUP_OBJS 。我们可以看看第一个输出:


下一个源码文件是 arch/x86/boot/header.S,但是我

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇FFmpeg编译一个仅带H264解码功能.. 下一篇[JavaScript]catch(ex)语句中的ex

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: