系统调用
系统调用是内核给用户程序提供的编程接口。用户程序调用系统调用,通常使用glibc库针对单个系统调用封装的函数。如果glibc库没有针对某个系统调用封装的函数,用户程序可以使用通用的封装函数syscall():
#define _GNC_SOURCE
#include <unistd.h>
#include <sys/syscall.h> /* 定义SYS_xxx */
long syscall(long number, ...);
参数number是系统调用号,后面是传递给系统调用的参数。
返回值0表示成功,返回值-1表示错误,错误号存储在变量errno中。
例如,应用程序使用系统调用fork()创建子进程,有两种调用办法:
(1)ret = fork();
(2)ret = syscall(SYS_fork);
ARM64处理器提供的系统调用指令是svc,调用约定如下:
(1)64位应用程序使用寄存器x8传递系统调用号,32位应用程序使用寄存器x7传递系统调用号
(2)使用寄存器x0~x6最多可以传递7个参数
(3)当系统调用执行完的时候,使用寄存器x0存放返回值。
1. 定义系统调用
Linux内核使用宏SYSCALL_DEFINE定义系统调用,以创建子进程的系统调用fork为例:
kernel/fork.c
SYSCALL_DEFINE0(fork)
{
#ifdef CONFIG_MMU
return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
#else
/* can not support in nommu mode */
return -EINVAL;
#endif
}
把宏“SYACALL_DEFINE0(fork)”展开以后是:
asmlinkage long sys_fork(void)
“SYSCALL_DEFINE”后面的数字表示系统调用的参数个数,“SYSCALL_DEFINE0”表示系统调用没有参数,“SYSCALL_DEFINE6”表示系统调用有6个参数,如果参数超过6个,使用宏“SYSCALL_DEFINEx”。头文件“include/linux/syscalls.h”定义了这些宏。
“asmlinkage”表示这个C语言函数可以被汇编代码调用。如果使用C++编译器,“asmlinkage”被定义为extern "C";如果使用C编译器,“asmlinkage”是空的宏。
系统调用的函数名称以“sys_”开头。
需要在系统调用表中保存系统调用号和处理

本文详细阐述了系统调用的概念,包括用户程序如何通过glibc库或直接使用syscall()函数调用系统调用,以及ARM64处理器上的系统调用指令svc的使用。深入探讨了Linux内核中系统调用的定义、执行流程,以及ARM64架构下系统调用的处理机制。
最低0.47元/天 解锁文章
1638





