【Linux系列】添加系统调用最新教程

  • 编译环境
  • 修改任务
    • 基础任务
    • 进阶任务
  • 修改准备
  • 修改源码
    • 添加系统调用号
    • 修改系统调用头文件
    • 修改系统调用函数定义
  • 编译安装内核
  • 编写主程序
  • 进阶任务
  • 总结

编译环境

  • 虚拟机操作系统: ubuntu-20.04.3-desktop-amd64
  • 原系统内核版本:5.11.0-46-generic
  • 内核源码版本:5.11.1

修改任务

基础任务

  • 采用内核编译法增加两个系统调用
  • 一个系统调用把用户输入的字符串保存到 text.txt
  • 一个系统调用把 text.txt 中的字符串读出
  • 写个主程序调用两个系统调用

进阶任务

  • 用户可以指定用户输入字符串保存的位置和文件名
  • 程序可以将系统调用读取出的字符串打印到用户终端

修改准备

  • 下载内核源码
  • 掌握内核编译

修改源码

  • 所需修改的文件(路径默认从源码目录开始)如下:
arch/x86/entry/syscalls/syscall_64.tbl      //设置系统调用号,如果是32位就用syscall_32.tblinclude/linux/syscalls.h                     //系统调用的头文件kernel/sys.c                                 //定义系统调用函数

添加系统调用号

  • 使用 gedit 打开 syscall_64.tbl 文件
sudo gedit arch/x86/entry/syscalls/syscall_64.tbl
  • 根据规则在后面添加自己的系统调用号和系统调用名,如下图所示

  • 这里我添加了两个系统调用分别是读和写

修改系统调用头文件

  • 使用 gedit 打开 syscalls.h 文件
sudo gedit include/linux/syscalls.h
  • 添加对应系统调用的函数声明,如下图
asmlinkage long sys_fwrite(int strcount,char __user* string);
asmlinkage long sys_fread(void);

修改系统调用函数定义

  • 使用 gedit 打开 sys.c 文件
sudo gedit kernel/sys.c
  • 添加对应系统调用的函数定义,内容如下:
//写文件系统调用
SYSCALL_DEFINE2(fwrite,int,strcount,char __user *,string)
{printk("fwrite executing");struct file *filp;char* filename="/usr/src/text.txt\0";printk("open file");filp = filp_open(filename, O_RDWR|O_TRUNC, 0755);if(IS_ERR(filp)){printk("open error...\n");return -1;}printk("writing\n");char* buf;buf = (char *)kmalloc(sizeof(char) * strcount, GFP_KERNEL);if(!copy_from_user(buf, string, strcount)){printk("input is %s \n", buf);}kernel_write(filp, buf, strlen(buf),&filp->f_pos);filp_close(filp,NULL);printk("fwrite end\n");return 0;}
// 读文件系统调用
SYSCALL_DEFINE0(fread)
{printk("fread executing");struct file *filp;struct inode *inode;const char* filename="/usr/src/text.txt\0";off_t fsize;char *buf;unsigned long magic;printk("start....\n");filp=filp_open(filename,O_RDONLY,0);inode=file_inode(filp);magic=inode->i_sb->s_magic;printk("file system magic:%li \n",magic);printk("super blocksize:%li \n",inode->i_sb->s_blocksize);printk("inode %li \n",inode->i_ino);fsize=inode->i_size;printk("file size:%i \n",(int)fsize);buf=(char *) kmalloc(fsize+1,GFP_ATOMIC);printk("buf correct\n");kernel_read(filp,buf,fsize,&(filp->f_pos));buf[fsize]='\0';printk("The File Content is:\n");printk("%s\n",buf);filp_close(filp,NULL);printk("fread end\n");return 0;
}
  • 将两个函数定义写在 sys.c 文件的尾部
  • 其中 SYSCALL_DEFINE 为系统定义,之后的数字代表系统调用参数的个数,其中第一个参数为系统调用函数的名称,需要与调用号定义(调用号定义第三个参),声明(sys_xxx中xxx部分)一致。
  • 注意系统调用定义时的参数书写格式。

编译安装内核

#编译内核
sudo make -j4#安装内核模块
sudo make modules_install#安装内核
sudo make install#重启
reboot

编写主程序

  • 在指定目录下新建文件 text.txt
sudo touch /usr/src/text.txt
  • 新建 readAndWrite.c 文件,内容如下
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/syscall.h>
#include<linux/kernel.h>
int main()
{long int a;printf("this is testwr execution\n");char string[120];scanf("%s",string);int length=strlen(string)+1;a = syscall(442,length,string);printf("a=%li\n",a);printf("testwr end\n");printf("this is testwr execution\n");a = syscall(443);printf("a=%li\n",a);printf("testwr end\n");return 0;}
  • 编译
gcc readAndWrite.c -o readAndWrite.o
  • 执行
sudo ./readAndWrite.o
  • 执行结果,如下图

  • 至此基础任务完成,接下来完成进阶任务

进阶任务

  • 重新添加新的系统调用

  • 添加系统调用号

  • 添加系统调用函数声明

asmlinkage long sys_fsize(int pathcount,char __user * path);
asmlinkage long sys_fwrite_advance(int strcount,char __user * string,int pathcount,char __user * path);
asmlinkage long sys_fread_advance(char __user * res,int pathcount,char __user * path);
  • 添加系统调用函数定义
//获取文件大小系统调用
SYSCALL_DEFINE2(fsize,int,pathcount,char __user *,path)
{printk("fsize executing");struct file *filp;struct inode *inode;off_t fsize;unsigned long magic;char* pathbuf;pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);if(!copy_from_user(pathbuf, path, pathcount)){printk("input path is %s \n", pathbuf);}printk("start....\n");filp=filp_open(pathbuf,O_RDONLY,0);inode=file_inode(filp);magic=inode->i_sb->s_magic;printk("file system magic:%li \n",magic);printk("super blocksize:%li \n",inode->i_sb->s_blocksize);printk("inode %li \n",inode->i_ino);fsize=inode->i_size;printk("file size:%i \n",(int)fsize);filp_close(filp,NULL);printk("fsize end\n");return fsize+1;
}
//写文件系统调用
SYSCALL_DEFINE4(fwrite_advance,int,strcount,char __user *,string,int,pathcount,char __user *,path)
{printk("fwrite_advance executing");struct file *filp;char* pathbuf;pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);if(!copy_from_user(pathbuf, path, pathcount)){printk("input path is %s \n", pathbuf);}printk("%s",pathbuf);printk("open file");filp = filp_open(pathbuf, O_RDWR|O_TRUNC, 0755);if(IS_ERR(filp)){printk("open error...\n");return -1;}printk("writing\n");char* buf;buf = (char *)kmalloc(sizeof(char) * strcount, GFP_KERNEL);if(!copy_from_user(buf, string, strcount)){printk("input is %s \n", buf);}kernel_write(filp, buf, strlen(buf),&filp->f_pos);filp_close(filp,NULL);printk("fwrite_advance end\n");return 0;}
//读文件系统调用
SYSCALL_DEFINE3(fread_advance,char __user *,res,int,pathcount,char __user *,path)
{printk("fread_advance executing");struct file *filp;struct inode *inode;off_t fsize;char *buf;unsigned long magic;char* pathbuf;pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);if(!copy_from_user(pathbuf, path, pathcount)){printk("input path is %s \n", pathbuf);}printk("start....\n");filp=filp_open(pathbuf,O_RDONLY,0);inode=file_inode(filp);magic=inode->i_sb->s_magic;printk("file system magic:%li \n",magic);printk("super blocksize:%li \n",inode->i_sb->s_blocksize);printk("inode %li \n",inode->i_ino);fsize=inode->i_size;printk("file size:%i \n",(int)fsize);buf=(char *) kmalloc(fsize+1,GFP_ATOMIC);printk("buf correct\n");kernel_read(filp,buf,fsize,&(filp->f_pos));buf[fsize]='\0';printk("The File Content is:\n");printk("%s\n",buf);if(!copy_to_user(res, buf, fsize+1)){printk("output success");}filp_close(filp,NULL);printk("fread_advance end\n");return 0;
}
  • 编译安装内核
  • 修改主程序
#include<unistd.h>
#include <stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/syscall.h>
#include<linux/kernel.h>
int main()
{long int a;printf("this is testwr execution\n");char *res;char string[120];char path[120];scanf("%s",string);scanf("%s",path);int length=strlen(string)+1;int plength=strlen(path)+1;a = syscall(444,length,string,plength,path);printf("a=%li\n",a);printf("testwr end\n");printf("this is testwr execution\n");a = syscall(446,plength,path);printf("a=%li\n",a);res = malloc(sizeof(char)*a);a = syscall(445,res,plength,path);printf("%s\n",res);printf("a=%li\n",a);printf("testwr end\n");return 0;}
  • 在所需目录下新建所需文件
  • 编译运行,结果如下

总结

  • 增加系统调用主要是修改三个文件,分别添加系统调用号、系统调用函数声明和系统调用函数定义
  • 增加文件读写系统调用的核心函数是:filp_open、filp_close、kernel_read、kernel_write、copy_from_user、copy_to_user
  • 关于文件读写和系统调用传参最大且最容易出现的问题往往是字符指针字符数组的问题

【Linux系列】添加系统调用相关推荐

  1. linux内核添加系统调用(详细)

    linux内核添加系统调用(详细) 说在前面: 这是我第五次编译内核,分别踩了很多坑.中途问过wz佬,佬让我用qemu.我还是最后换ubuntu虚拟机跑了.现在已经有点emo了. 这篇博客是我第五次的 ...

  2. MIPS(loongson)linux 中添加系统调用

    在基于MISP(loongson)架构处理器与基于 x86 架构处理器的 linux 内核中添加系统调用时更改的文件是不同的,x86 中需要更改 arch/x86/kernel/syscall_tab ...

  3. ie传递给系统调用的数据区域太小_【Linux系列】系统调用

    在现代OS中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限地访问硬件设备,提供了创建新进程并与已有进程进行通信的机制,也提供了申请OS其他资源的能力. 系统调用在用户空间进程和硬 ...

  4. linux内核syscall_define6,linux中添加系统调用

    1)在内核里添加系统调用,函数形式是:asmlinkage type sys_func_name(...) 2)在文件include/asm-arm/unistd.h里面添加 define __NR_ ...

  5. ubuntu 10.10 添加系统调用的方法

    主要参考以下文章 向linux内核中添加三个系统调用(Ubuntu9.10) - 耕耘--IT - 博客园     内核编译的过程(网上收集) - 小楠楠 - 博客大巴     编译内核(2.6.11 ...

  6. 添加系统调用的方法,2.6.35(没有测试)

    转载:http://www.cnblogs.com/kenjones/archive/2011/03/09/1978611.html ubuntu 10.10 添加系统调用的方法 http://lxr ...

  7. Linux内核2.6.34.14添加系统调用及编译方法(CentOS-6.4-x86_64)

    <?xml version="1.0" encoding="UTF-8"?> //我添加系统调用步骤,仅供参考,尤其是系统调用的实现部分,建议大家自 ...

  8. linux 3.5.0-23-generic内核版本系统调用数目,Linux操作系统分析(三)- 更新内核与添加系统调用...

    环境:Ubuntu 12.10     学号:SA****199 1.更新内核: 直接安装的系统内核版本一般不是最新,用 uname -a 查看一下 自己的版本,OK,我的是: Linux chenh ...

  9. 【Linux】Linux添加系统调用以及内核编译过程

    在想要替换原有系统内核或者需要在原来的系统中添加一些系统调用的时候就会涉及到Linux内核的编译.但是内核编译虽然步骤简单,但是需要注意的东西还是太多了.首先一点就是由于Linux的开源性导致的版本问 ...

最新文章

  1. Java虚拟机调用jni_JNI攻略之十一――启动虚拟机调用java类
  2. 学习Pygame和巩固Python——画颜色~
  3. IE7及以下浏览器不支持json的解决方法
  4. [FFmpeg] ffmpeg 常用命令
  5. android8 通知呼吸灯_正在消失的功能,为什么越来越多的手机没有呼吸灯?你知道原因吗...
  6. C# Regex 深入正则表达式
  7. 在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能
  8. 基于Java Bean Validation对Request参数进行校验的设计思路
  9. Handler: Service中使用Toast
  10. .NET中加密和解密的实现方法
  11. [团队项目]英语学习助手之 NABC 模型
  12. dlna android电视,DLNA怎么用?DLNA连接智能电视和电脑的方法分享
  13. 数学----三角函数公式推导
  14. VS与OpenGL画蜗型线、心形线、三叶曲线、四叶曲线、螺旋线(内附修改教程)
  15. C语言实现简易三子棋,支持双人对战,电脑可拦截
  16. 初学素描需要准备的工具有哪些?新手必看!
  17. 大数据技术——模板虚拟机环境准备
  18. 04.一语详解SpringBoot全局配置文件
  19. 数据分析前景如何,如何规划学习路线
  20. 云端安装神经网络环境(cuda10.1ppc64)

热门文章

  1. 通过一张模糊的照片,判断拍摄的具体位置
  2. 单片机c语言孔雀开屏,毕业设计(论文)-人形机器千手观音动作实现研究.doc
  3. MFC笔记:GDI+贴图、双缓冲绘图、向屏幕上输出文字
  4. Tesseract .Net SDK C# OCR 2022.1
  5. HTTP Debugger Pro使用教程
  6. -Werror=deprecated-declarations
  7. 第四章 分治策略 4.4 用递归树方法求解递归式
  8. MySQL数据库索引:删除、查看、创建索引
  9. 模拟信号转PWM输出隔离转换器 输出驱动能力可达 5A
  10. pythontxt文件操作_Python读写txt文本文件的操作方法全解析