一目了然系列之 linux 内核编译(思路篇)

内核编译

内核自己编译的意义

  • 定制编译的内核因为使用的代码少的原因运行的会更快,减少了不必要的设备支持。
  • 定制内核大小比通用内核的小,这样会减少内存的消耗,因为内核要运行在内存中。
  • 用不上的功能就不编译,这样会减少很多的漏洞被利用。
  • 编译灵活,有强烈需求的直接 build-in 到内核里面,不是核心需求的可以编译成模块,这样的话内核自己的体积就变小了。根据自己需求来做,灵活方便。

先说几个概念

vmlinuz

vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接。vmlinuz的建立有两种方式。一是编译内核时通过“make zImage”创建,然后通过:“cp /usr/src/linux-x.x/arch/i386/linux/boot/zImage /boot/vmlinuz”产生。zImage适用于小内核的情况,它的存在是为了向后的兼容性,适用于小内核。二是内核编译时通过命令make bzImage创建,然后通过:“cp /usr/src/linux-x.x/arch/i386/linux/boot/bzImage /boot/vmlinuz”产生。简单来说正常的发型版本的linux 都是用的大内核,用的是 bzImage 方式制作的。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件,一般没有什么地方使用vmlinux,用的地方少,这里只介绍一下。

initrd.img

initrd.img 初始 RAM 磁盘(initrd)是在实际根文件系统可用之前挂载到系统中的一个初始根文件系统。initrd 与内核绑定在一起,并作为内核引导过程的一部分进行加载。内核然后会将这个 initrd 文件作为其两阶段引导过程的一部分来加载模块,这样才能稍后使用真正的文件系统,并挂载实际的根文件系统。initrd 中包含了实现这个目标所需要的目录和可执行程序的最小集合,例如将内核模块加载到内核中所使用的 insmod 工具。在桌面或服务器 Linux 系统中,initrd 是一个临时的文件系统。其生存周期很短,只会用作到真实文件系统的一个桥梁。在没有存储设备的嵌入式系统中,initrd 是永久的根文件系统。

System.map

System.map 内核符号映射表,顾名思义就是将内核中的符号(也就是内核中的函数)和它的地址能联系起来的一个列表。是所有符号及其对应地址的一个列表。之所以这样就使为了用户编程方便,直接使用函数符号就可以了,而不用去记要使用函数的地址。当你编译一个新内核时,原来的System.map中的符号信息就不正确了。随着每次内核的编译,就会产生一个新的 System.map文件,并且需要用该文件取代原来的文件。System.map是一个特定内核的内核符号表。它是你当前运行的内核的System.map的链接。

内核编译的方法

1.下载并解压内核

内核下载官网:https://www.kernel.org/ 可以看到有好几个类型分别是 mainline 主线,就是当前在开发的最新的内核。stable 是当前稳定版的最新代码。longterm 这个是长期支持版,一般的发行版本里面都会采用的就是这种长期支持版。下载好内核的页码之后对源码进行解压,在解压好的目录里面进行各种配置。

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz
tar xf linux-5.1.16.tar.xz

2.定制内核:make menuconfig

make mrproper ,第一遍下载下来编译的时候,不用做,后面还是用这个源码就必须要做,这个命令的意义是删除陈旧没用的文件,保持源码的干净。

在正常的发行版本上,内核都是编译好的,而且配置文件都会保存在 /boot 文件夹里面写好,想偷懒的话
cp /boot/config-$(uname -r) .config 可以这样来做,因为这个内核肯定是能够满足你现在的需求的,现在用着的内核就是基于这个配置来做的。用下面的 make menuconfig 就是为了生成这个.config的文件,这个文件就记录着哪些需要编译,那些不用。可以说内核编译就是围绕着这个文件去做的,所做的一切都是为了生成这个文件,然后根据这个文件里面记录的内容去编译对应的模块。

定制编译内核可用到下面的几个命令。

make config 基于文本的最为传统的配置界面,不推荐使用
make menuconfig 基于文本选单的配置界面,字符终端下推荐使用
make xconfig 基于图形窗口模式的配置界面,Xwindow下推荐使用
make oldconfig 如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦

选择相应的配置时,有三种选择,它们分别代表的含义如下:
  Y--将该功能编译进内核
  N--不将该功能编译进内核
  M--将该功能编译成可以在需要时动态插入到内核中的模块

说说 make menuconfig 菜单

这是 make defconfig 生成出来的基本配置

[*] 64-bit kernel
# 64位系统内核
General setup  --->
# 一般设置
[*] Enable loadable module support  --->
# 支持加载的模块
-*- Enable the block layer  --->
# 块设备支持,使用硬盘/USB/SCSI设备者必选这选项使得块设备可以从内核移除。如果不选,那么 blockdev 文件将不可用,一些文件系统比如 ext3 将不可用。这个选项会禁止 SCSI 字符设备和 USB 储存设备,如果它们使用不同的块设备。选Y,除非你知道你不需要挂载硬盘和其他类似的设备。不过此项无可选项
Processor type and features  --->
# 处理器类型和功能
Power management and ACPI options  --->
# 电源选项
Bus options (PCI etc.)  --->
# pci总线
Executable file formats / Emulations  --->
# 可执行文件格式
[*] Networking support  --->
# 网络支持
Device Drivers  --->
# 设置驱动
Firmware Drivers  --->
# 固件驱动
File systems  --->
# 文件系统
Kernel hacking  --->
# 内核调试技术  
Security options  --->
# 安全选项
-*- Cryptographic API  --->
# 提供核心的加密API支持
[*] Virtualization  --->
# 虚拟化
Library routines  --->
# 内核原码中的第三方内核模块才可能需要

这个展开说可以写10几篇这里不展开说了,以后有时间一点一点磨,这里我用的是方便的方法把 `/boot` 下面 centos7 内核编译的配置文件`config-3.10.0-957.21.3.el7.x86_64 ` 复制成 `.config`,然后执行 `make menuconfig` 去掉我不需要的东西,这里有个方法,根据 `lspci` 出来的设备去查看,这是自己机上的硬件,然后在根据这个硬件的列表去删除对应的组件。最后执行 `make -j8`

编译

编译很简单, 内核编译选项设置好之后, 只需简单的命令 make, 就可以编译了.
由于内核代码的庞大, 所以和一般应用程序相比, 编译时间会很长. 可以尝试以下方法来加快编译速度:

不用的驱动程序都不要设置, 这样就不会编译
利用make的 -j 选项来并发编译, ex. make -j N (N是并发数). 如果你的机器有2个CPU, 可以用 make -j 4 来提高编译速度
使用 make localmodconfig 来生成仅以正在使用的内核模块为对象的 .config (一般这样生成的.config中包含的内核模块最少, 所以编译速度快)

前面配置好了内核,那么我们现在就要编译内核了,直接用 make -j 4 命令进行编译,在make meunconfig的过程中有些东西是由模块来实现的,现在我们开始编译模块,这里使用的命令是 make modules_install
生成内核模块和vmlinuz,initrd.img,Symtem.map文件

vmlinuz是可引导的、压缩的内核,“vm”代表“Virtual Memory”。如果内核比较小,那么可以采用zImage 或bzImage之一,两种方式引导的系统运行时是相同的。大的内核采用bzImage,不能采用zImage。 vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。

安装内核和模块:sudo make modules_install install

复制模块文件到/lib/modules目录下、复制config,vmlinuz,initrd.img,Symtem.map文件到/boot目录、更新grub

其他命令:

make mrprobe:命令的作用是在每次配置并重新编译内核前需要先执行“make mrproper”命令清理源代码树,包括过去曾经配置的内核配置文件“.config”都将被清除。即进行新的编译工作时将原来老的配置文件给删除到,以免影响新的内核编译。
make dep:生成内核功能间的依赖关系,为编译内核做好准备。

写着写着发现这个篇幅实在太大了,在这先起个头。介绍一些概念和思路,细节的东西后面再写了。

参考资料,排名不分先后,感谢这些前辈们留下的这些资料:
https://www.linuxprobe.com/linux-kernel-compilation.html
https://blog.csdn.net/zhenguo26/article/details/79641322
https://linux.cn/article-9665-1.html
https://blog.csdn.net/geekcome/article/details/6558754
https://www.ibm.com/developerworks/cn/linux/l-initrd.html
https://blog.csdn.net/geek_tank/article/details/69479196
https://www.cnblogs.com/unicode/archive/2010/05/20/1739702.html

上一篇
下一篇