Linux内核编译和系统调用-血的教训
Linux内核编译和系统调用
- 前言
- 前期准备
- 首先知道自己linux系统的内核
- 提前准备以下库(防止中间报错)
- 找到合适的准备编译的内核版本
- 修改代码-准备实现系统调用
- 下载内核版本
- 修改sys.c文件
- 修改syscalls.h文件
- 加入系统调用号(这里特别重要)
- 编译内核
- 验证系统调用
- 需要注意的问题
- 1.要留出充足的空间
- 2.在配置.config文件时要删除点东西
- 3.grub引导
- 总结
前言
这真的是血的经历,这个内核编译差不多搞了四天,出了很多错,多次崩溃,所以为了让各位少踩点坑,我准备写个博客来记录一下,希望有需要的各位少走点弯路-请务必关注最后的需要注意的问题
我用的虚拟机系统是Ubuntu20.04
前期准备
首先知道自己linux系统的内核
可以使用命令
uname -r
可以看到我内核的版本是5.11.0-38-generic。
提前准备以下库(防止中间报错)
sudo apt-get install libncurses5-dev sudo apt-get install libssl-dev sudo apt-get install bison sudo apt-get install flex
找到合适的准备编译的内核版本
比如我这里的内核版本是5.11.0,需要下载的准备编译的内核应该比我这个版本高,网站如下网站

版本别高太多,最好找个稳定版(stable),这样可以少打点补丁。
我试了三个内核,最后还是选择只高一个版本也就是5.11.1
修改代码-准备实现系统调用
下载内核版本
将目录切换进 /usr/src下,下载内核(这里改为你想下载的版本)然后解压(可能需要等一段时间)
sudo wget https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.11.1.tar.xz
xz -d linux-5.11.1.tar.xz
tar -xvf linux-5.11.1.tar
然后进入内核
cd linux-5.11.1
修改sys.c文件
这个文件在linux-5.11.1/kernel下
sudo gedit kernel/sys.c
在最后的#endif前加入以下代码(这里可以自己随便加-我是想实现输出一段数字)
SYSCALL_DEFINE1(boris,long,number){printk("My number is %ld\n",number);return 2817;
}
注意这里的DEFINE1是指我有一个参数也就是long number(同样的道理,如果为DEFINE2表示两个参数比如参数列表为(boris,long,number,int,flag)),这里的boris是我系统调用函数的名字-可以自己随便设。然后保存
修改syscalls.h文件
为了给这个boris加入声明,这个文件在include/linux里
sudo gedit include/linux/syscalls.h
我是在sys.c注释的那一段里的最后加入了声明(我不知道这个位置是否有影响,因为试错成本太高)
asmlinkage long sys_boris(long number);
加入系统调用号(这里特别重要)
首先要知道自己的机器是32位还是64位,使用
getconf LONG_BIT
可以看到我的是64位,所以加入系统调用号要在syscall_64.tbl中(32位机器就在syscall_32.tbl中)
sudo gedit arch/x86/entry/syscalls/syscall_64.tbl
加入以下
请记住这个335(以个人情况定),这个335是系统调用号,后面会遇到,这个335也是前面的系统调用号+1,还有就是不要把这一行写到x32那一部分会报错。
编译内核
sudo make mrproper
sudo make clean
第一行清除内核的目标文件、附属文件以及配置文件,第二行清楚内核中目标文件,不清除配置文件
然后是配置.config文件
sudo make menuconfig
之后会出现图形化配置
这里选择sava,ok(这里会说已经written in the .config),exit即可,这里有需要注意的地方,请看最后需要注意的问题
接下来,到了激动人心的时候,编译
sudo make -j2
这里jn是指线程数,可按自己虚拟机来决定,我机器比较拉跨,只能j2,线程数越多越快

这里需要等待很久,我大概等了两三个小时,所以如果错了,会非常绝望,非常耗时,之前代码千万不要写错
看到这里有一段Kernel:arch/x86/boot/bzImage is ready就可以踏实了,说明万里长征已成功了一大半,如果想知道自己中间哪里出错可以把信息写入日志,比如sudo make -j2 > error.txt (使用重定向)
接下来是编译模块
sudo make modules_install
这里可能等十分钟左右
再输入命令
sudo make install
我看到了曙光
这里看到了5.11.1,完成并没报错,查看内核版本
uname -r
看到了什么,我太激动了,5.11.1,折腾了四天才弄出来的玩意。
验证系统调用
写一个C语言程序,代码如下
#include<stdio.h>
int main(int argc,char*argv[]){//这里我们之前的系统调用号就派上了用场-之前就是335long flag=syscall(335,2817);printf("My ID is %ld\n",flag);return 0;
}
然后编译执行

使用如下命令输出系统调用函数printk输出的值
sudo dmesg -c
需要注意的问题
1.要留出充足的空间
可以使用如下命令查看空间是否足够
df -h
我是40个G,一般编译内核最后留出最少大约15G,容量不足可考虑扩容

2.在配置.config文件时要删除点东西
sudo gedit .config
这里的CONFIG_SYSTEM_TRUSTED_KEYS要置空即将里面内容删去,不然会报错
3.grub引导
cd /boot/grub
可以看到里面有一个grub.cfg文件,你的开机引导就在里面,建议要对其操作之前对其进行备份(cp)。
如果更新grub可以使用
sudo update-grub2
然后重启
reboot
总结
内核编译一定要有耐心,也和你本身系统内核版本和你准备编译的内核版本有关,所以要多尝试,只不过会付出大量的时间成本,但不要放弃,我试了四天不也搞出来了,建议记录下报错的信息,这些信息很有价值。希望大家可以少踩点坑,能对内核编译和系统调用有一个良好的体验。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
