1. 环境
Ubuntu 的具体版本:Ubuntu 22.04.4 LTS
内核版本:6.9.8
gcc版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
2. 具体实现步骤
(1)将内存开到100G,防止编译过程中内存不够而报错。处理器可以根据自己电脑配置设置(加快编译速度)
(2)查看现有版本:uname -r
(3)在虚拟机浏览器中打开链接(The Linux Kernel Archives),下载6.9.8
(4)下载完成后,在“下载”页面打开终端,将压缩包移动到/usr/src目录下,移动命令:
sudo cp linux-6.9.8.tar.xz /usr/src
(5)在/usr/src目录下,查看是否移动成功。再在/usr/src目录下打开终端解压文件。解压命令(在root用户下,防止权限问题):
tar -xvf linux-6.9.8.tar.xz
(6)修改系统调用表
打开在/usr/src/linux-6.9.8/arch/x86/entry/syscalls路径下的syscall_64.tbl文件目录,打开终端,修改系统调用表命令:
sudo gedit syscall_64.tbl
<<462为增加的系统调用号,64为系统调用的参数个数,mycall为调用函数名,sys_mycall为系统调用的内核函数名称(格式要与上一行格式相同)>>注意:两数之间不是空格是Tab缩进。
(7)实现系统调用函数
打开在/usr/src/linux-6.9.8/kernel路径下的sys.c文件目录下,打开终端,,添加上自己的系统调用函数的声明,修改命令:
sudo gedit sys.c
在文件最下一行添加函数(按G直接跳转最后一行)
(8)添加系统调用头文件
打开在/usr/src/linux-6.9.8/include/linux路径下的syscalls.h文件目录下,打开终端,添加上自己的系统调用函数的声明,修改命令:
sudo gedit syscall.h
(9)安装编译内核所需的依赖包(全部下载成功,否则会编译出错)
sudo apt-get update
sudo apt-get install make
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
sudo apt-get install pkg-config
sudo apt-get install libssl-dev
sudo apt-get install libelf-dev
sudo apt-get install bison
sudo apt-get install flex
(10)编译内核(在cd /usr/src/linux-6.9.8目录下进行)
1)清除内核编译过程产生的中间文件,如果之前编译过内核源码,由于出错或者其它原因想重新编译,则需要先清理下之前的编译结果
sudo make mrproper
2)清除以前生成的目标文件和其他文件
sudo make clean
3)配置编译参数
sudo make menuconfig
配置编译参数,编译的内核模块选择,出现以下界面。并且修改此文件需在 sudo make clean ;sudo make mrproper指令之后执行,不然修改过的.config文件又会复原。
操作过程:Save--->ok--->Exit--->Exit
4)
sudo gedit .config
将下面两行的“”内的内容删除成这样子后保存,否则会报错(编译内核错误——*** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止)
5)make加上-jn选项多线程编译内核来加速内核编译(根据自己设置的处理器内核总数设置)(花了将近三个小时)
sudo make -j8
7)安装模块,大概需要十几分钟
sudo make modules_install
8)查看是否安装成功
在/lib/moudles目录下查看
是否生成内核压缩镜像文件,在/arch/x86/boot下查看生成bzImage
10)安装内核
sudo make install
11)更改系统启动参数
update-grub2
12)重启进入新内核
sudo reboot
13)查看内核版本,内核替换成功
uname -a
3. 运行及测试
(1)代码
测试代码test.c:
#include<stdio.h>
#include<stdlib.h>
#include<linux/kernel.h>
#include<sys/syscall.h>
#include<unistd.h>
int main()
{
printf("dll' mycall: %ld\n", syscall(462, 20221911));//若返回值为-1,调用失败;若返回值为0,调用成功(因为我在系统调用函数的声明时,设置返回值为0,可以设置自己想要返回的值)
}
(2)运行命令
(3)运行./test(返回值不为-1,调用成功)
(4)查看日志:sudo dmesg(系统调用成功)