警告
本文最后更新于 2022-10-21,文中内容可能已过时。
Linux Kernel
内核(kernel)
内核版本
在 https://www.kernel.org/ 上可以看到最新的稳定版,在我写文时最新版本是 5.16.15
内核编译
安装编译所需的库
1
sudo apt - get install libncurses5 - dev build - essential kernel - package ibdw - dev dwarves zstd libssl - dev libelf - dev
内核文件下载与解压
想要编译内核,首要的肯定是先把源码下载下来,这里给出几个下载地址(镜像站)。在我的网络环境下,北京交通大学的镜像站速度最快。
1
2
3
4
5
https://www.kernel.org/pub/
https://mirrors.edge.kernel.org/pub/linux/kernel
https://mirrors.tuna.tsinghua.edu.cn/kernel/
https://mirror.bjtu.edu.cn/kernel/linux/kernel/
https://mirrors.ustc.edu.cn/kernel.org/linux/kernel/
我这里选择的是我编写文章时的最新版
1
2
linux-5.16.15.tar.xz 121.7 MiB 2022-03-16 21:36
https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.16.15.tar.xz
使用 wget 对文件进行下载,使用 tar 对压缩包进行解压
1
2
wget https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/linux-5.16.15.tar.gz
tar -xzvf linux-5.16.15.tar.gz
编译选项配置
1
2
cd linux-5.16.15
make menuconfig
打开后会出现这样的界面,可以在里面来调整一些编译选项,具体操作可以看顶部的介绍。
我们这里开启调试相关的选项
勾选 Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info
,现在似乎是默认开启的。
如果需要使用 kgdb 调试内核,则需要选中 Kernel hacking -> Generic Kernel Debugging Instruments -> KGDB: kernel debugger
下的所有选项,我这里暂时不需要,故不开启。
全部设置完毕后,选择 Save
保存设置。
编译内核
可以根据机器的核数来选择具体配置,编译过程大概十分钟左右。
1
2
3
4
编译主体
sudo make bzImage -j8
编译模块
sudo make modules -j8
编译成功后会提示,本机是 x86 的,默认编译了 x86 的内核
1
Kernel: arch/x86/boot/bzImage is ready (#3)
坑点
make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。
搜索到一些相关内容,似乎是因为编译机器不是 Debian 系统,这个位置没有证书,解决方案如下
搜索到以下配置项并修改为
1
2
CONFIG_SYSTEM_TRUSTED_KEYS=""
CONFIG_SYSTEM_REVOCATION_KEYS=""
交叉编译 ARM64
编译过程有少许的不同
从 ARM64 路径下复制默认配置
1
cp ./arch/arm64/configs/defconfig .config
配置选项
在原来的编译命令上,添加 ARCH 来指定目标指令集
1
make menuconfig ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
编译内核
从 bzImage 变成了 Image,编译后在根目录下会产生 vmlinux*,arch/arm64/boot/ 下会产生 Image 和 Image.gz
1
make Image -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
内存文件系统(initrd)
BusyBox
可以使用 busybox 来构建一个简单的文件系统
编译 BusyBox
在 https://busybox.net/ 可以找到 busybox 的最新版本,我这里编译 BusyBox 1.35.0
下载源码
1
2
wget https : // busybox . net / downloads / busybox - 1.35 . 0. tar . bz2
tar - xvf busybox - 1.35 . 0. tar . bz2
配置
1
2
cd busybox-1.35.0
make menuconfig
在 Setttings 选中 Build static binary (no shared libs),将 busybox 编译为静态链接的文件 在 Linux System Utilities 中取消选中 Support mounting NFS file systems on Linux < 2.6.23 (NEW),关闭网络文件系统 在 Networking Utilities 中取消选中 inetd,关闭 Internet 超级服务器 编译
1
2
make -j8
make install
在源码根目录下就会有一个 _install
目录,下面存放着编译好的文件
BusyBox 交叉编译
对于 busybox 来说,在 menuconfig 中就可以直接配置交叉编译,具体位置在 Settings -> Cross compiler prefix
,可以将其设置为 aarch64-linux-gnu-
(对于编译 aarch64 来说)
配置后和原来一样编译就可以得到一份 aarch64 架构的 busybox
配置文件系统
1
2
cd _install
mkdir -p proc sys dev etc/init.d
添加启动文件,并且加上可执行权限
1
2
gedit etc/init.d/rcS
chmod +x etc/init.d/rcS
init 文件内容
1
2
3
4
5
6
7
8
9
10
#!/bin/sh
echo "INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
echo -e "Boot took $( cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 1000 /bin/sh
打包文件系统
1
find . | cpio -o --format=newc > ../rootfs.img
Buildroot
https://buildroot.org/download.html
Buildroot 下载与解压
1
2
wget https : // buildroot . org / downloads / buildroot - 2022.02 . tar . xz
tar - xvf buildroot - 2022.02 . tar . x
编译选项配置
1
2
cd buildroot-2022.02
make menuconfig
在弹出的配置界面中:
1
2
3
4
5
6
7
8
9
10
Target options ---> 选择目标板架构特性。
Build options ---> 配置编译选项。
Toolchain ---> 配置交叉工具链,使用 buildroot工具链还是外部提供 。
System configuration ---> 配置生成的根文件系统中所需功能
Kernel ---> 配置 kernel是否编译以及编译选项
Target packages ---> 配置生成的根文件系统中的工具以及库
Filesystem images ---> 配置生成的根文件系统的格式,是 ext2还是其他
Bootloaders ---> 配置使用哪种 bootloader以及编译选项 , uboot只是其中一种
Host utilities ---> 主机使用功能
Legacy config options ---> 以前遗留的配置选项
交叉编译
Target option ---> Target Architecture
为 AArch64 (little endian)
Toolchain ---> Toolchain type
为 External toolchain
,这时我们可以看到 Toolchain ---> Toolchain
的值为 Arm AArch64 xxxx.xx
设置密码
System configuration ---> Enable root login with password
开启System configuration ---> Root password
为 xxxx
(任意的你喜欢的密码)交叉编译
System configuration ---> Run a getty (login prompt) after boot ---> TTY port
的值为 ttyAMA0
(这一条非常重要,不然虚拟机可能启动不了,如果出现 can’t open /dev/ttyAMA0: No such file or directory,就改回 console)Target packages ---> Show packages that are also provided by busybox
开启Target packages ---> Debugging, profiling and benchmark ---> strace
开启Filesystem images ---> cpio the root filesystem
开启。启动欢迎语
System configuration ---> System hostname
System configuration ---> System banner
配置网卡 DHCP
System configuration ---> Network interface to configure through DHCP
编译源码
编译过程中使用到 wget,可能需要代理
坑点
gdb 编译失败
报错内容为 错误: ‘LONG_MIN’未声明(在此函数内第一次使用)
尝试添加以下 PATCH
buildroot/package/gdb/版本/0007-fix-LONG_MIN-undefined-in-libiberty.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
From 5385e269 c6ce1e0525628f378942315442a5841e Mon Sep 17 00 : 00 : 00 2001
From : zhongw < service @ t - firefly . com >
Date : Sat , 21 Dec 2019 10 : 08 : 28 + 0800
Subject : [ PATCH ] fix LONG_MIN undefined in libiberty
Signed - off - by : zhongw < service @ t - firefly . com >
---
libiberty / fibheap . c | 16 ++++++++++++++++
1 file changed , 16 insertions ( + )
diff -- git a / libiberty / fibheap . c b / libiberty / fibheap . c
index a37ee4e .. b344b17 100644
--- a / libiberty / fibheap . c
+++ b / libiberty / fibheap . c
@@ - 34 , 6 + 34 , 22 @@ Boston , MA 02110 - 1301 , USA . */
#include "libiberty.h"
#include "fibheap.h"
+/* FIXME : It 'd be nice to configure around these, but the include files are too
+ painful . These macros should at least be more portable than hardwired hex
+ constants . */
+
+ #ifndef ULONG_MAX
+ #define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */
+ #endif
+
+ #ifndef LONG_MAX
+ #define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF */
+ #endif
+
+ #ifndef LONG_MIN
+ #define LONG_MIN ((long)(~LONG_MAX)) /* 0x80000000 */
+ #endif
+
#define FIBHEAPKEY_MIN LONG_MIN
buildroot/package/gdb/版本/0008-fix-to-use-fcntl-include-in-libiberty.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
From 9 dbe3dd463ac209cf9dc99d83e9446ca743ad0ec Mon Sep 17 00 : 00 : 00 2001
From : zhongw < service @ t - firefly . com >
Date : Sat , 21 Dec 2019 10 : 17 : 55 + 0800
Subject : [ PATCH ] fix to use fcntl include in libiberty
Signed - off - by : zhongw < service @ t - firefly . com >
---
libiberty / pex - unix . c | 4 ++++
1 file changed , 4 insertions ( + )
diff -- git a / libiberty / pex - unix . c b / libiberty / pex - unix . c
index b48f315 .. b27d699 100644
--- a / libiberty / pex - unix . c
+++ b / libiberty / pex - unix . c
@@ - 28 , 6 + 28 , 10 @@ Boston , MA 02110 - 1301 , USA . */
#include <stdio.h>
#include <signal.h>
#include <errno.h>
+
+/* Define to 1 if you have the < fcntl . h > header file . */
+ #define HAVE_FCNTL_H 1
+
#ifdef NEED_DECLARATION_ERRNO
extern int errno ;
#endif
添加后,需要先 make clean,再重新 make,此时会把新加入的 Patch 文件应用
QEMU 中添加网卡后网络无法使用
方法一
需要在编译选项中配置网卡 DHCP,然后重新 sudo make clean、sudo make
方法二
如果你不想重新编译的话,也可以直接修改配置文件 buildroot/output/target/etc/network/interfaces
1
2
3
4
5
6
7
8
9
10
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
pre-up /etc/network/nfs_check
wait-delay 15
hostname $(hostname)
重新启动后可以看到使用 udhcpc 去获取 DHCP 分配的 IP 地址
ipconfig 也能够正常显示出 IP 地址
Qemu 模拟环境
接下来就要用 qemu-system-xxx 来启动我们编译好的内核,不过首先先对相关的配置参数做一个介绍
常用的选项
-m, 指定 RAM 大小,默认 384M -kernel,指定内核镜像文件路径 -initrd,设置内核启动的内存文件系统 -smp [cpus=]n[,cores=cores][,threads=threads][,dies=dies][,sockets=sockets][,maxcpus=maxcpus]
,指定使用到的核数。-cpu,指定指定要模拟的处理器架构,可以同时开启一些保护,如+smap,开启 smap 保护 +smep,开启 smep 保护 -nographic,表示不需要图形界面 -monitor,对 qemu 提供的控制台进行重定向,如果没有设置的话,可以直接进入控制台,对于出题来说,最好设置为 null -append,内核参数(以空格分开的一个字符串列表)nokaslr
关闭随机偏移console=ttyS0,和 nographic
一起使用,启动的界面就变成了当前终端。 root=xxx,告诉内核启动时使用哪个设备作为根文件系统,如果是某个分区,可以用 /dev/hda8
;如果是在内存上,可以用 /dev/mem
。 init=… 告诉内核在启动后执行哪个程序。如果该选项未被设置,将会启动/sbin/init rootwait 告诉内核无限期等待,直到根文件系统出现。对于 U 盘等设备,设备的发现是异步的,如果在发现 USB 设备之前挂载根文件系统,则内核会找不到根文件系统,造成启动失败。