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

相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩4 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言