Linux源码编译、调试和阅读
下载内核源码
下载 Linux 官方 Git 仓库:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
# or: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
(可选)增添开发版本的远程分支
cd linux
git remote add linux-next https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
# or: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
git fetch linux-next
git fetch --tags linux-next
编译启动内核
安装工具链
与平台无关的:
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
与平台相关的:
sudo apt install gcc-aarch64-linux-gnu
编译配置
使用默认配置
在Linux源码目录下,执行配置程序,如下:
make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" defconfig
其中
defconfig
是default configuration
的意思ARCH
表示交叉编译的硬件架构,实际上就是arch目录下的子目录名称。在Linux中,ARM64 就是arm64
,而不是aarch64
。CROSS_COMPILE
会拼接到 gcc,即${CROSS_COMPILE}gcc
,上面的结果是aarch64-linux-gnu-gcc
。
如果想输出到其它目录中,可以加O=/path/to/output-dir
,然后下面的操作切换到对应的输出目录中执行,这样便将Linux源码和编译结果分离,可以在不同目录下生成不同平台的内核镜像。示例:
make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" O=/home/yuanyin/syslab/arm64-linux/linux defconfig
!!!下文假设是在/home/yuanyin/syslab/arm64-linux/linux
目录下执行编译。
配置调试信息
解决一些配置依赖的问题:
make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" menuconfig
(1)添加调试信息:
打开 DEBUG_INFO
对应选项。根据工具链决定那一项就好了。
Kernel hacking
Compile-time checks and compiler options
Debug information
(2)关闭RANDOMIZE_BASE
取消地址随机化:关掉RANDOMIZE_BASE
选项,对应的prompt是:Randomize the address of the kernel image。
-> Processor type and features // -> Kernel features │
-> Build a relocatable kernel
[] Randomize the address of the kernel image (KASLR)
保存退出!!!
执行编译
使用 bear
工具生成 compile_commands.json
文件(JSON Compilation Database),用于代码分析。
sudo apt install bear
make clean # if compiled
bear -- make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" -j $(nproc)
最后会生成:
- 包含编译参数的
compile_commands.json
文件 - 内核镜像
arch/arm64/boot/Image
- 带调试信息的镜像
vmlinux
- 符号到地址的映射
System.map
。
yuanyin@zyynote:~/syslab/arm64-linux/linux$ ls
arch crypto include kernel mm modules-only.symvers net sound usr vmlinux.o
block drivers init lib modules.builtin modules.order scripts source virt vmlinux.symvers
certs fs ipc Makefile modules.builtin.modinfo Module.symvers security System.map vmlinux
制作文件系统
请移步 制作 Linux 根文件系统,那里有详细介绍如何简单地制作一个根文件系统。
QEMU启动内核镜像
安装对应平台的QEMU
例如安装AARCH64平台的QEMU,执行下面安装:
sudo apt install qemu-system-arm
启动脚本:
qemu-system-aarch64 -machine virt -cpu cortex-a53 \
-machine type=virt -nographic -smp 2 \
-m 2048 \
-kernel linux/arch/arm64/boot/Image \
--append "console=ttyAMA0 root=/dev/vda init=/linuxrc rw" \
-hda rootfs.ext2
其中 rootfs.ext2
是ext2文件系统格式的硬盘,-hda
表示硬盘。--append
后面加入的是传递给内核的命令,console=ttyAMA0
表示控制台输出设备,ARM64架构这里是ttyAMA0
,root
就是跟文件系统所在的磁盘分区,而init
就是Linux启动的第一个程序所在位置,可以自由定义。
注意:在 x86 中是
"console=ttyS0 root=/dev/sda init=/linuxrc rw"
调试方法
注意:首先要在启动脚本中加入-s -S
选项。可以直接使用GDB命令行进行调试,也可以使用VS Code提供的图形界面进行调试。
方式一:命令行调试
安装gdb-multiarch
支持跨平台调试:
sudo apt-get intall gdb-multiarch
然后执行gdb-multiarch
,进入GDB界面。
执行如下连接QEMU:
set architecture aarch64
target remote localhost:1234
在 GDB 交互界面中导入调试信息:
file /path/to/vmlinux
方式二:使用 VS Code 调试和阅读
配置启动文件
.vscode/launch.json
文件配置如下:
{
"version": "0.2.0",
"configurations": [
{
"name": "arm64-linux debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/../arm64-linux/linux/vmlinux",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb-multiarch",
"targetArchitecture": "arm64",
"miDebuggerServerAddress": "127.0.0.1:1234",
}
]
}
配置C/C++属性文件
用于阅读源码:增加 compile_commands.json
配置项,如下:
{
"configurations": [
{
"name": "Linux",
"forcedInclude": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu11",
"intelliSenseMode": "linux-gcc-x64",
"compileCommands": "${workspaceFolder}/../arm64-linux/linux/compile_commands.json"
}
],
"version": 4
}
注意:符号定义跳转的时候可能会比较卡。
网络配置
User mode networking
缺点:不允许从外面连接进来,不推荐。
TAP interfaces
!!!不需要操作,直接看综合配置小节。
查看当前工作主机的路由表,可以看到
(1)所有Destination为0.0.0.0
这一项,表示所有的IP都通过网卡eth0
到网关172.18.144.1
去。
(2)所有符合IP为172.18.144.0
掩码 255.255.240.0
的报文无效,参考链接。
匹配的时候以匹配最长的IP字段为准。
$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.18.144.1 0.0.0.0 UG 0 0 0 eth0
172.18.144.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
(1)打开主机的转发功能
先查看主机是否转发报文:
$ cat /proc/sys/net/ipv4/ip_forward
0
# 或者
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
开启主机的转发功能:
sudo sysctl net.ipv4.ip_forward=1
(2)创建虚拟交换机
$ sudo ip link add zyybr0 type bridge
$ sudo ip link set zyybr0 up
# or
# brctl addbr zyybr0 (deprecated)
# ifconfig zyybr0 up
给交换机分配地址:
$ sudo ifconfig zyybr0 192.168.1.1/24
使用主机转发交换机内容
$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
(3)创建交换机网口
$ sudo ip tuntap add zyytap0 mode tap
$ sudo ip link set dev zyytap0 up
# or tunctl command (deprecated)
将网口和交换机绑定
$ sudo ip link set zyytap0 master zyybr0
(4)QEMU配置
...
-netdev tap,id=zyynet0,script=no,downscript=no,ifname=zyytap0 \
-device virtio-net-device,netdev=zyynet0 \
...
(5)配置客户端系统
ifconfig eth0 192.168.1.20
route add default gw 192.168.1.1
配置DNS服务器
# cat /etc/resolv.conf
nameserver 8.8.8.8
综合配置
QEMU启动脚本
sh ifup.sh
qemu-system-aarch64 -machine virt -cpu cortex-a53 \
-machine type=virt -nographic -smp 2 \
-m 2048 \
-kernel linux/arch/arm64/boot/Image \
--append "console=ttyAMA0 root=/dev/vda init=/linuxrc rw" \
-netdev tap,id=zyynet0,script=no,downscript=no,ifname=zyytap0 \
-device virtio-net-device,netdev=zyynet0 \
-hda rootfs.ext2
sh ifdown.sh
先执行启动脚本
sudo sysctl net.ipv4.ip_forward=1 > /dev/null
sudo ip link add zyybr0 type bridge
sudo ip link set zyybr0 up
sudo ip tuntap add zyytap0 mode tap
sudo ip link set dev zyytap0 up
sudo ip link set zyytap0 master zyybr0
sudo ifconfig zyybr0 192.168.1.1/24
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
在根文件系统的/etc/init.d/rcS
或者其它配置文件中加入:
ifconfig eth0 192.168.1.20
route add default gw 192.168.1.1
echo "nameserver 8.8.8.8" > /etc/resolv.conf
关掉qemu后执行
sudo iptables -t nat --flush
sudo ip addr flush dev zyybr0
sudo ip link set dev zyytap0 down
sudo ip tuntap del zyytap0 mode tap
sudo ip link set zyybr0 down
sudo ip link del dev zyybr0 type bridge
sudo sysctl net.ipv4.ip_forward=0 > /dev/null
参考:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY