实 验 名 称 | 系统调用 |
- 实验目的
(1)学习 Linux 内核的系统调用方法。
(2)理解并掌握Linux 系统调用的实现框架、用户界面、参数传递、进入/返回过程
- 实验内容
根据 8.2 节描述的两种方法添加一个不用传递参数的系统调用,其功能是简单输出类似“helloworld!”这样的字符串。
- 实验步骤
1.使用内核编译法添加系统调用
(1)获取root权限
(2)进入kernel目录
# cd /usr/src/linux-5.4.100/kernel
(3)打开sys.c并在其中加人如下函数,如图8.1所示。
asmlinkage long sys helloworld(void){
printk("hello world!");
return 1;}
(4)添加声明。
#cd /usr/src/linux-5.4.100/arch/x86/include/asm/
# vim syscalls.h
在syscallsh 中加人如下函数声明:
asmlinkage long sys helloworld(void);
(5)添加一个系统调用号。
#cd/usr/src/linux-5.4.100/arch/x86/entry/syscalls
# vim syscall_64.tbl
在系统调用表(其最前面的属性是id)中添加一个id 为335的系统调用号,添加后保存syscall 64.tbl文件,如图所示。
(6)配置内核。
# cd /usr/src/linux-5.4.100
清除旧目标文件并重新配置内核,依次执行以下语句(与第 7 章类似)。
# sudo make mrproper
# sudo make clean
# sudo make menuconfig
为了更明显地看到编译的内核版本,可以在makeconfig 时将 General setup 界面上的
Localversion修改成新的名称,如myKernel,如图所示。
(7)编译和安装内核(与实验1类似)。
#sudo make -j8
# sudo make modules -j8
# sudo make modules_install
# sudo make install
(8)重启系统。
#reboot
# uname -r
2. 使用内核模块法添加系统调用
使用内核模块法添加系统调用的步骤如下。
- 编写 hello.c文件,内容如下
(2)查询 sys call table 的地址。
可以使用sudo cat /proc/kallsyms|grep sys_call table命令来查询sys_call table 的地址
(3)编写Makefile文件,可参考如下内容:
(4)编译 hello 模块并将其装入系统。
make
sudo insmod hello.ko
lsmod
- 实验结果
1.内核编译法
编写hello.cpp文件
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main(){
long int a= syscall(335);
printf("system call sys helloworld reutrn %ld\n",a);
return 0;
}
gcc hello.cpp
./a.out
2.内核模块法
编写test2.c文件,内容如下
编译并运行测试程序
查看系统日志输出
五、实验总结
1.出现的问题及其原因与解决方案
问题1:系统调用未被识别或无法找到
原因:系统调用未正确注册或相关的头文件和函数声明未正确配置。
解决方案:在添加系统调用之前,确保正确注册系统调用并将相关的头文件和函数声明添加到适当的位置。需要修改内核源代码和相关的系统调用表。
问题2:系统调用无法正常工作或返回错误 不能正确输出
原因:可能存在逻辑错误、内存访问问题、权限问题等。
解决方案:仔细检查系统调用的实现代码,确保逻辑正确。检查内存访问是否正确、指针是否被正确初始化和释放,以及权限是否正确设置。使用调试工具(如GDB)进行调试,以找出问题所在。
问题3:系统调用执行结果不成功返回值为-1
原因:make没完全编译,重新编译
解决方案:检查系统调用的实现代码,发现没用问题。于是重新编译,再次尝试。
2.总结体会:
本次实验使用了内核编译法添加一个不用传递参数的系统调用,实验过程较为顺利,有一下一些总结:
- vim命令的使用
vi(visual editor)编辑器通常被简称为vi,它是Linux和Unix系统上最基本的文本编辑器,类似于Windows 系统下的notepad(记事本)编辑器。Vim(Vi improved)是vi编辑器的加强版,比vi更容易使用。vi的命令几乎全部都可以在vim上使用。
vim编辑器有三种模式:
命令模式、编辑模式、末行模式
模式间切换方法:
(1)命令模式下,输入:后,进入末行模式
(2)末行模式下,按esc慢退、按两次esc快退、或者删除所有命令,可以回到命令模式
(3)命令模式下,按下i、a等键,可以计入编辑模式
(4)编辑模式下,按下esc,可以回到命令模式
- 关于Linux添加系统调用
首先需要编写系统调用的具体实现代码,可以是一个 C 函数或汇编代码,根据需求和系统调用的功能来决定。每个系统调用都有一个唯一的系统调用号,接下来就需要在内核的系统调用表中为新的系统调用分配一个未使用的号码,这通常需要修改内核源代码。在本次实验中就对vim kernel/sys.c文件进行了修改,并在vim syscalls.h添加了调函数声明,在arch/x86/entry/syscalls/syscall_64.tbl添加第335个调用号。在修改内核源代码后,需要编译和安装修改后的内核。这一步有了实验1的基础就较为清晰明了了。值得注意的是,对内核进行修改和编译是一个复杂的过程,并且可能涉及系统的低级操作。错误的修改可能导致系统不稳定或不可用。因此在进行任何内核修改之前,有必要充分了解其实现过程,通过本次的实验,我对内核编译法有了较为深入的理解。
另外,对于指导书上提到的另一种方法即内核模块法。其实现步骤主要为创建一个内核模块的源代码文件,其包含了所要添加系统调用的具体实现。然后编写系统调用的具体实现,即在内核模块的源代码文件中,编写要添加的系统调用的具体实现代码。其次,在内核模块中注册系统调用:在内核模块的初始化函数中,使用 syscall_register 函数将系统调用注册到内核中。并为系统调用指定一个唯一的系统调用号,并将其与系统调用的实现函数关联起来。最后编译和加载内核模块,即编译内核模块源代码文件,并生成一个内核模块对象文件。使用 insmod 命令将内核模块加载到内核中。在加载内核模块后,即可编写用户空间的测试程序来调用新的系统调用。