Linux 内核编译与系统调用

任务

​ 编译内核
​ 增加一个系统调用
CentOS 上编译内核 V4.10.1,并添加一个系统调用

xz 格式文件

如何创建和解压.xz 格式文件?以解压linux-3.12.tar.xz为例

解压 xz 格式文件

首先用 xz-utils 的 xz 命令将 linux-4.18.15.tar.xz 解压为 linux-4.18.15.tar
其次用 tar 命令将 linux-4.18.15.tar 完全解压

1
2
3
xz –d linux-4.18.15.tar.xz
tar –xf linux-4.18.15.tar
或 tar –Jxf linux-4.18.15.tar.xz

创建 xz 格式文件

首先利用 tar 命令将 linux-4.18.15 文件夹打包成 linux-4.18.15.tar
其次用 xz-utils 的 xz 命令将 linux-4.18.15.tar 压缩成 linux-4.18.15.tar.xz

1
2
3
tar –cf linux-4.18.15.tar linux-4.18.15/
xz –z linux-4.18.15.tar
或 tar –Jcf linux-4.18.15.tar.xz linux-4.18.15/

Linux 内核编译

首先用 cat /etc/redhat-releaseuname -msr 命令查看当前系统的内核情况

002

发现是 CentOS 系统,用 yum 安装一些需要的编译工具

1
2
yum update
yum install –y ncurses-devel make gcc bc bison flex elfutils-libelf-devel openssl-devel grub2

3

cd /usr/src 进入 /src 目录底下准备下载想要编译的内核文件

这里我选用最新的稳定版本 4.18.15

4

tar.xz 文件解压后进入目录

cp /boot/config-$(uname -r) .config 复制当前正在运行的内核的配置文件

make menuconfig 可以配置 Linux 内核

7

由于我们刚刚复制了正在运行的配置,所以可以直接退出不用管它

查看计算机配置并编译

9

确保编译命令在 /usr/src/linux-4.18.15目录下执行

1
2
3
4
5
make bzImage
make modules
make
make modules_install
make install

编译时若遇见 gcc: Internal error: Killed (program cc1) 错误,是因为编译过程需要大量的内存,可以开启 swap 分区继续编译

编译完成后 reboot 命令重启服务器

重启后查看发现内核版本号不对

13

找到配置文件 /boot/grub/grub.conf,可以看到 default=1 默认启动的内核是CentOS (2.6.32-754.6.3.el6.x86_64)

11

将 default 值置为 0 并重启

14

如上图所示,内核替换成功

添加新的系统调用

先查看一下系统的调用表

vim /usr/src/linux4.18.15/arch/x86/entry/syscalls/syscall_64.tbl

在文件末端添加自己的系统调用函数以及对应的系统调用编号(335为本文添加)

001

vim include/linux/syscalls.h

在末端加入系统调用函数的声明

002

vim kernel/sys.c

文件末端加入对应的实现函数

003

1
2
3
4
5
6
make oldconfig  //一直按回车即可
make –j4 //4指多线程编译的个数
make modules_install
make install
reboot
uname -sr

14

编写一个简单的 test.c 的文件并编译

cat /proc/kallsyms | grep mysyscall 确认调用新的系统函数

005

010

新版本内核中的系统函数 include/linux/syscalls.h 文件以及 kernel/sys.c 文件都有了一些变动

之前以为没有影响用dmesg命令查看编译结果结果最后的发现i溢出了

最后决定选用4.10.14版本的内核重复上述过程

006

007

008

编译完成后,编写 test.c 文件测试

./out 执行生成文件

004

用 demsg 查看结果

009

调用成功!

报错汇总

编译模块环节遇到了错误

10

经查询发现编译过程中内存耗尽, 导致了编译中断,可能是系统没有交换分区, 解决方法是增加一个交换分区

  1. 创建分区文件, 大小 2G

    dd if=/dev/zero of=/swapfile bs=1k count=2048000

  2. 生成 swap 文件系统

    mkswap /swapfile

  3. 激活 swap 文件

    swapon /swapfile

这样就木有问题了, 但是这样并不能在系统重启的时候自动挂载交换分区, 这样我们就需要修改 /etc/fstab 文件, 新增如下内容:

/swapfile swap swap defaults 0 0

could not find moudle 错误

12

在make install时,为了让新内核中不缺少所需module,会先检查当前系统已经加载了的module(lsmod命令可查看),然后对比新安装的内核模块,如果新的内核模块中缺少一些module(和当前lsmod命令的输出做对比),就会报 ERROR: modinfo: could not find module power_meter 这样的错误信息。

具体来说,缺少相应module而报错,大致可分为3种情况:

  1. 确实是缺少了某个 module,其解决方法是:如果报的 module 对于你来说是有用,检查编译 kernel 时的 .config 文件,加上对应的配置(配为=m),重新编译和安装 modules 即可;如果你觉得这个module没啥用,就不必管它。

  2. 新编译的 kernel 已经将该选项编译进 kernel 了(.config中选择为=Y),从而不需要生成这个 module的 .ko 文件,系统找不到对应的 .ko文件,但是已经在新内核中了,不必理会这个报错。

  3. 模块的名称变了,用当前系统 lsmod 命令查找的模块名称,在新编译的内核中找不到 module 了。只需要检查确认即可,如这里的 ERROR: modinfo: could not find module power_meter 就是这种类型,检查方式如下:

最后,如果那些错误报的内核模块,你认为不重要或者都经过上面的分析解决后,你就可以忽略这些错误提示了;尽管有这些 ERROR: modinfo: 错误提示,但是 kernel 还是被正确安装了的,往下继续操作使用即可。

参考链接:

https://brennan.io/2016/11/14/kernel-dev-ep3/
https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/