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/

  • 14
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值