在 Linux 6.8 中创建自定义系统调用

大家好!我是大聪明-PLUS

你是否曾经想过创建自己的系统调用?也许你曾被布置过这样的作业,也许你出于好奇尝试过,又或许只是为了学习一些关于内核的新知识。无论如何,系统调用都是深入了解 Linux 的绝佳途径。

❯ 本指南有哪些吸引人的地方?

关于这个主题,市面上也有其他一些指南,但问题在于它们没有跟上内核发展的步伐------内核发展太快了。很多指南不仅过时,而且还包含大量错误。这就是我决定写这篇文章的原因,同时也是为了找出并修正这些错误。

❯ 准备系统以进行内核编译

在基于 Red Hat/Fedora/Open SUSE 的发行版上,您可以简单地执行以下操作:

复制代码
`Sudo dnf builddep kernel
Sudo dnf install kernel-devel`

在基于 Debian/Ubuntu 的发行版中:

复制代码
`sudo apt-get install build-essential vim git cscope libncurses-dev libssl-dev bison flex`

❯ 我们得到核心

我们将克隆内核源代码分支,具体目标是 6.8 版本。但是,这里描述的说明也应该适用于更新的内核版本(当然,除非内核开发人员再次更改整个过程)。

复制代码
`git clone --depth=1 --branch v6.8 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git`

理想情况下,克隆版本的内核版本应该与当前安装的内核版本不相上下。

您可以使用以下命令检查当前内核版本:

复制代码
`uname -r`

❯ 创建一个新的系统调用

让我们执行以下代码:

复制代码
`cd linux
make mrproper
mkdir hello
cd hello
touch hello.c
touch Makefile`

因此,我们将hello在加载的内核代码中直接创建一个名为" "的目录,并在该目录中放入两个文件------hello.c系统调用代码和一个 Makefile,该 Makefile 以规则的形式规定了如何创建同一个文件。

用你最喜欢的文本编辑器打开它hello.c,并将以下代码写入其中:

复制代码
`#include <linux/kernel.h>
#include <linux/syscalls.h>

SYSCALL_DEFINE0(hello) {
 pr_info("Hello World\n");
 return 0;
}`

内核日志将显示" Hello World"。

由于我们只想在屏幕上显示信息,我们将使用n=0

接下来,将以下文本添加到 Makefile 文件中:

复制代码
`obj-y := hello.o`

现在:

复制代码
`cd ..
cd include/linux/`

让我们打开此目录中的文件" " syscalls.h,并添加:

复制代码
`asmlinkage long sys_hello(void)`

这是我们上面创建的系统调用函数的原型。

打开内核根目录(cd ../..)下的文件" Kbuild",并在文件末尾添加以下内容:

复制代码
`obj-y += hello/`

这样我们就告诉内核构建系统编译我们刚刚包含的目录。

处理完这个问题后,我们还需要将系统调用指定为描述架构的表格中的一个新条目。

每个 CPU 架构都有其特定的系统调用,因此程序需要指明我们正在运行的架构。

文件x86_64内容如下:

复制代码
`arch/x86/entry/syscalls/syscall_64.tbl`

您应该在此处添加系统调用条目。请记住,您只能为其分配一个当前未被使用的编号,并且切勿使用表注释中禁止使用的编号。

当时我的房间号是462,所以就添加了一条新的入住记录,如下所示:

复制代码
`462 common hello sys_hello`

这里,462 映射到我们的系统调用,这是两种架构的常见做法。我们的系统调用名为 hello,其入口点为sys_hello

❯ 编译并安装新内核

让我们运行本节列出的命令。

既然我们已经讨论完了所有允许的事情,接下来让我们看看禁止的事情吧 ;)

复制代码
`cp /boot/config-$(uname -r) .config
make olddefconfig
make -j $(nproc)
sudo make -j $(nproc) modules_install
sudo make install`

在这里,我们复制当前加载内核的配置文件,告诉构建系统使用与配置文件中相同的值,其他所有参数保持默认值。然后,我们根据可用核心数(由 nproc 指定)构建支持并行处理的内核。之后,我们自行承担风险安装已构建的内核。

编译内核需要很长时间,所以不妨给自己泡杯咖啡,欣赏一下终端里一行行的命令吧。

整个过程可能需要几个小时,具体取决于您的系统速度。您的电脑风扇可能会高速运转以防止过热(是的,我经历过这种情况)。

❯ 最有趣的是:我们使用了一个新的系统调用

现在我们的系统调用已经集成到内核中,让我们重新启动系统,并确保在启动时从 grub 中选择新的(修改过的)内核。

启动后,让我们编写一个 C 程序来使用这个系统调用。

让我们创建一个名为" "的文件,例如,test.c该文件将包含以下内容:

复制代码
`#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
int main(void) {
  printf("%ld\n", syscall(462));
  return 0;
}`

这里,请替换 462 为您在表格中为新系统调用指定的编号。

编译并运行程序。

复制代码
`make test
chmod +x test
./test`

如果一切顺利," "将出现在命令行中0,并且系统调用的输出将在所有内核日志中可见。

我们通过以下方式访问日志dmesg

复制代码
`sudo dmesg | tail`

瞧,您将在这里看到系统调用输出的消息。

恭喜你,你做到了!但请允许我提醒你以下几点:

  • 编译内核需要很长时间;

  • 新编译的内核会占用相当大的空间,所以请确保你有足够的空间;

  • Linux内核代码变化迅速。

相关推荐
一个平凡而乐于分享的小比特2 小时前
零拷贝技术详解:从传统IO到极致优化
linux·零拷贝
大聪明-PLUS2 小时前
使用 Linux 命令轻松构建数据库
linux·嵌入式·arm·smarc
一个平凡而乐于分享的小比特2 小时前
核心原理:文件系统 vs 归档格式
linux·文件系统·归档格式
鸠摩智首席音效师2 小时前
如何在 Linux 中使用 fallocate 命令 ?
linux·运维·服务器
秋深枫叶红2 小时前
嵌入式第四十三篇——数据库
linux·数据库·学习·oracle
淡忘_cx2 小时前
Ubuntu 24 飞牛虚拟机 ens2 网卡自动获取 IP(DHCP)配置文档
linux·tcp/ip·ubuntu
QT 小鲜肉2 小时前
【Linux命令大全】001.文件管理之split命令(实操篇)
linux·运维·服务器·网络·笔记
musk12122 小时前
在 Win11 PowerShell 中通过 SSH 密钥实现无密码访问 Linux 服务器,公钥使用 方法2 手动复制
linux·ssh·win11
松涛和鸣2 小时前
42、SQLite3 :字典入库与数据查询
linux·前端·网络·数据库·udp·sqlite