在 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内核代码变化迅速。

相关推荐
天才奇男子20 小时前
HAProxy高级功能全解析
linux·运维·服务器·微服务·云原生
学嵌入式的小杨同学20 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
酥暮沐21 小时前
iscsi部署网络存储
linux·网络·存储·iscsi
❀͜͡傀儡师21 小时前
centos 7部署dns服务器
linux·服务器·centos·dns
Dying.Light21 小时前
Linux部署问题
linux·运维·服务器
S190121 小时前
Linux的常用指令
linux·运维·服务器
小义_1 天前
【RH134知识点问答题】第7章 管理基本存储
linux·运维·服务器
梁洪飞1 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
_运维那些事儿1 天前
VM环境的CI/CD
linux·运维·网络·阿里云·ci/cd·docker·云计算
Y1rong1 天前
linux之文件IO
linux