linux实训 为Linux添加一个系统调用
为linux添加一个系统调用 操作步骤
美好的一天从智慧填埋开始
Linux 实训内容让我们在Linux系统内核中添加一个系统调用,我刚开始看到这个实验我大意了,书上的版本和我电脑装的虚拟机版本严重不符,所以上网查找资料,完成实验,特此记录一下。
我的虚拟机是版本
Linux 3.10.0-1160.el7.x86_64
CentOS 7.9.2009
CentOS 7.9.2009 的rpm包
链接: https://pan.baidu.com/s/1kKJ0M_L5KWU7LEOUlKr2Lw?pwd=ej86 提取码: ej86
安装虚拟机 上述版本虚拟机 参考我的另一篇
https://blog.csdn.net/LYGCSDN_/article/details/124847501?spm=1001.2014.3001.5502
下载对应的版本的内核源代码
首先查看CentOS 版本下载对应的rpm包
下载网址https://vault.centos.org/
选择目录 7.9.2009
接着进入目录 os
然后 Source
最后 SPackages
找到名字为 kernel-3.10.0-1160.el7.src.rpm 的rpm包,如果是其他版本网页上搜索kernel,找到带src的就是,然后点击下载,然后上传到自己的服务器或者虚拟机上去。
获取源代码压缩包
在rpm包目录下,执行下面代码
rpm -ivh kernel-3.10.0-1160.el7.src.rpm
注:这里可能会报错
消除警告的方式是创建mockbuild用户和用户组,执行一下代码
groupadd mockbuild
useradd mockbuild -g mockbuild
再次执行
rpm -ivh kernel-3.10.0-1160.el7.src.rpm
解压源代码压缩包
会在目录 /root/rpmbuild/SOURCES 下有一个 linux-3.10.0-1160.el7.tar.xz 的压缩包
进入该目录下 执行 解压命令
tar -xJf linux-3.10.0-1160.el7.tar.xz
添加一个 函数调用
进入目录下
/root/rpmbuild/SOURCES/linux-3.10.0-1160.el7/kernel
在路径下找到sys.c ,在该文件最后添加自定义函数 sys_mycall()
asmlinkage long sys_mycall(long number){
//这里long 类型要用 %ld 不然编译会报错
//这里是printk 不是 printf 调用该函数时 可以用dmesg 看到打印信息,后面会讲到
printk("software 201 people number:%ld",number);
return number;
}
添加系统调用函数声明
/root/rpmbuild/SOURCES/linux-3.10.0-1160.el7/include/linux
syscalls.h 添加函数声明
/root/rpmbuild/SOURCES/linux-3.10.0-1160.el7/arch/x86/syscalls/
目录下的 syscall_64.tbl
设置64位调用
定义系统调用宏 宏号
/root/rpmbuild/SOURCES/linux-3.10.0-1160.el7/include/uapi/asm-generic 目录下
打开 unistd.h
将 /root/rpmbuild/SOURCES/linux-3.10.0-1160.el7复制到/usr/src目录下
配置内核
进入 /usr/src/linux-3.10.0-1160.el7/ 目录下
编译内核和安装内核
依次输入这四条语句
sudo make mrproper
sudo make clean
sudo make menuconfig
此时会报错
需要下载ncurses
我的CentOs 所以使用下载命令:
yum install -y ncurses-devel
安装后再执行sudo make menuconfig
内核编译配置界面
[* ]:代表的是默认编译到内核
[M]:代表的是内核模块,编译过程中会编译该模块,但是不会编译到内核,需要用命令加载。
[ ]就是不编译该模块
当然你想把M(内核模块)改为*(编译到内核),直接在高亮选中下直接输入’Y’或者’y’。又或者不想编译该模块就直接输入’N’或者’n’。
这里直接 用方向键 选择 Save
Ok -> 回车 选中Exit
执行编译
根据自己处理器的最大线程数目来编译.
sudo make -j4
等待编译 快的话几十分钟 慢的话几个小时 根据你给该虚拟机分配的处理器个数
安装内核
首先安装 elfutils-libelf-devel 执行以下命令
yum install elfutils-libelf-devel
编译后安装内核到系统中.
sudo make modules_install
sudo make install // 安装内核(卡住 不动 不要着急 等几分钟 )
重新启动
选择新编译的内核版本
测试
vim test.c
#include<stdio.h>
#include<linux/kernel.h>
#include<sys/syscall.h>
#include<unistd.h>
int main (){
// syscall_64.tbl 定义声明332
long s = syscall(332,30);
printf("%ld",s);
return 0;
}
输入 dmesg 查看 printk打印内容
总结
用户空间和内核空间之间,有一个叫做Syscall(系统调用, system call)的中间层,是连接用户态和内核态的桥梁。这样即提高了内核的安全型,也便于移植,只需实现同一套接口即可。Linux系统,用户空间通过向内核空间发出Syscall,产生软中断,从而让程序陷入内核态,执行相应的操作。对于每个系统调用都会有一个对应的系统调用号,比很多操作系统要少很多。
1、asmlinkage是gcc标签,代表函数读取的参数来自于栈中,而非寄存器。
2、系统调用号的宏定义:位于文件 unistd.h,记录着内核空间的系统调用号,格式为#define__NR_xxx (__NR_SYSCALL_BASE+[num])
3、系统调用的函数声明:位于文件syscalls.h,格式为asmlinkage long sys_xxx(args …);
4、 用户空间的方法xxx,对应系统调用层方法则是sys_xxx;故mycall()方法 对应系统调用层便是sys_mycall(),该函数定义在 sys.c 文件中
,每个Syscall都有唯一的系统调用号对应,其宏定义unistd.h 中**__NR_mycall**系统调用号=291
syscalls.h中有如下声明:
5、kernel 会将开机信息存储在 ring buffer 中。若是开机时来不及查看信息,可利用 dmesg 来查看。开机信息亦保存在 /var/log 目录中。内核通过 printk() 输出的信息具有日志级别,用户执行的时候不能直接看到 内部信息,要用到dmesg命令
6、做这个实验的时候 最好不要分20G 内存,多分点内存,可能会报错,(惨痛教训,编译了一晚上 第二天看到这东西,很无奈 )
参考:http://gityuan.com/2016/05/21/syscall/
更多推荐
所有评论(0)