Linux系统调用及示例
来源:互联网 发布:nodejs调用java api 编辑:程序博客网 时间:2024/06/02 03:43
学习linux系统调用时先明确一个概念:一般情况下,应用程序通过应用编程接口API而不是直接通过系统调用来编程
应用编程接口API与系统调用的关系如下:(应用程序编程接口实际上并不需要和内核提供的系统调用对应)
(1)一个API可以实现成一个系统调用
(2)一个API可以通过调用多个系统调用来实现
(3)一个API可以完全不使用任何系统调用
来说说系统调用的一些共性吧:
1.系统调用(在linux中常称作syscalls)通常通过函数进行调用
2.它们通常都需要定义一个或几个参数
3.系统调用通常会通过一个long类型的返回值来表示成功或者错误
注意:用一个负的返回值来表明错误;用一个0值通常(不绝对)表明成功
系统调用号很重要:
每个系统调用被赋予一个系统调用号,系统调用号关联系统调用,当用户空间的进程执行一个系统调用的时候,这个系统调用号就被用来指明到底是要执行哪个系统调用,进程不会提及系统调用的名称。注意:系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。此外,如果一个系统调用被删除,它所占用的系统调用号也不允许被回收利用,否则,以前编译过的代码会调用这个系统调用,造成混乱。(linux有一个“未实现”系统调用sys_ni_syscall(),它除了返回-ENOSYS外不做任何其他工作,如果一个系统调用被删除,或者变得不可用,这个函数就要负责“填补空位”)
系统调用表(sys_call_table):
表中存放每个的系统调用的入口地址(函数指针);
每一个体系结构都有对应的一个系统调用表;
如x86平台的系统调用表arch/x86/kernel/syscall_table_32.S
如ARM平台的系统调用表arch/arm/kernel/entry-common.S
ENTRY(sys_call_table)
#include"calls.S"//arch/arm/kernel/calls.S文件内容如下:
Linux内核的唯一访问接口是系统调用,不同平台下的系统调用数目不一样,在ARM中,通用的系统调用有390个。通过修改内核的源码,增加第391个系统调用到内核中。
第一步:往内核添加一个自定义系统调用
在内核源码的arch/arm/kernel/sys_arm.c 文件中添加一个系统调用的实现:
gedit arch/arm/kernel/sys_arm.c
在文件最后添加如下代码,这个就是系统调用的实现代码:
asmlinkage long sys_foo(void)
{
printk("my syscallsys_foo!\n");
return THREAD_SIZE;
}
第二步:将系统调用添加到系统调用表中gedit arch/arm/kernel/calls.S
在系统调用号为390后面添加,如下蓝色部分
/* 385 */ CALL(sys_memfd_create)
CALL(sys_bpf)
CALL(sys_execveat)
CALL(sys_userfaultfd)
CALL(sys_membarrier)
CALL(sys_mlock2)
CALL(sys_foo)
第三步:添加系统调用号gedit arch/arm/include/uapi/asm/unistd.h
在系统调用号为390后面添加,如下蓝色部分
#define __NR_bpf (__NR_SYSCALL_BASE+386)
#define __NR_execveat (__NR_SYSCALL_BASE+387)
#define __NR_userfaultfd (__NR_SYSCALL_BASE+388)
#define __NR_membarrier (__NR_SYSCALL_BASE+389)
#define __NR_mlock2 (__NR_SYSCALL_BASE+390)
#define __NR_foo (__NR_SYSCALL_BASE+391)
第四步:修改系统调用数目
gedit arch/arm/include/asm/unistd.h
#include <uapi/asm/unistd.h>
/*
*This may need to be greater than __NR_last_syscall+1 in order to
*account for the padding in the syscall table
*/
#define __NR_syscalls (392) //该值要大于等于”最大的系统调用号+1”并且为4的整数倍,对齐
第五步: 添加系统调用函数的声明到头文件中gedit include/linux/syscalls.h
在文件的最后添加如下蓝色部分;
asmlinkage long sys_open_by_handle_at(int mountdirfd,
struct file_handle __user *handle,
int flags);
asmlinkage long sys_setns(int fd, int nstype);
asmlinkage long sys_foo(void);
#endif
第六步:添加完毕后,重新编译内核,并且使用重新编译的内核来启动开发板make uImage LOADADDR=0x40008000 -j2
以上就是添加一个系统调用的过程,可通过一下应用程序做测试:
#include <linux/unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
long stack_size;
stack_size= syscall(391);//系统一般会通过c库来调用系统调用,但是自己定义的系统调用缺少c库的支持,只能使用宏来调用系统调用
printf("Thekernel stack size is %ld\n",stack_size);
return0;
}
交叉编译上面的测试程序,在开发板上运行查看效果- Linux系统调用及示例
- linux下 hook 系统调用示例
- Linux - 文件属性及目录相关系统调用
- 进程结束及Linux中的系统调用
- Linux内核编译及添加系统调用
- Linux的IO系统常用系统调用及分析
- Linux的IO系统惯用系统调用及分析
- Linux RPC远程调用示例
- Unix/Linux操作系统的体系结构及系统调用介绍
- Linux下汇编程序及系统调用的深入分析
- Linux系统内核模块函数调用及命名空间
- Linux系统内核模块函数调用及命名空间
- Linux系统内核模块函数调用及命名空间
- Linux内核空间和用户空间及系统调用
- Linux系统调用及用户编程接口(API)学习
- Linux 操作系统内核升级及系统调用的添加
- Linux系统调用及用户编程接口(API)学习
- Linux系统调用及用户编程接口(API)
- python input()
- [译] Node.js, Express.js 搭建 HTTP/2 服务器
- 常用排序算法的时间复杂度以及空间复杂度
- ACM公约数和公倍数
- python学习笔记1:动态类型模型
- Linux系统调用及示例
- find 的详细使用
- RHEL 6.3使用CentOS yum源
- 关于java文件路径问题
- MySql优化-索引命中
- vim全局替换命令
- Neo4J(Cypher语句)学习
- centos JAVA环境变量设置(全局永久)
- study