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

总结

内核编译一定要有耐心,也和你本身系统内核版本和你准备编译的内核版本有关,所以要多尝试,只不过会付出大量的时间成本,但不要放弃,我试了四天不也搞出来了,建议记录下报错的信息,这些信息很有价值。希望大家可以少踩点坑,能对内核编译和系统调用有一个良好的体验。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部