0 前言
本文以x86和arm平台的为例重点分析Linux各版本的系统调用的实现和使用方法。
1 查看
可通过man查看有哪些系统调用,以及特定函数是否为系统调用[4]:
(1)方法1:man syscalls
(2)方法2:man <func_name>
2 声明
从linux-2.6.12到6.5.13,都可在下面头文件之一找到系统调用的声明:
头文件 | 说明 |
include/linux/syscalls.h | Linux syscall interfaces (non-arch-specific) 例如:sys_open、sys_read、sys_write |
arch/x86/include/asm/syscalls.h | Linux syscall interfaces (arch-specific) 例如:sys_mmap |
include/asm-generic/syscalls.h | Calling conventions for these system calls can differ, so it's possible to override them. 例如:sys_mmap |
include/trace/events/syscalls.h | ftrace相关接口 |
例如平台无关部分声明如下:
...
asmlinkage long sys_time(time_t __user *tloc);
asmlinkage long sys_stime(time_t __user *tptr);
asmlinkage long sys_gettimeofday(struct timeval __user *tv,
struct timezone __user *tz);
...
// @file: linux-2.6.39/include/linux/syscalls.h
3 定义
多数系统调用都以C函数,但有一些特殊系统调用是汇编定义的。
3.1 汇编
例如arm的sys_syscall、sys_mmap2等系统调用,都是直接使用汇编定义的:
/*============================================================================
* Special system call wrappers
*/
sys_syscall:
...
ENDPROC(sys_syscall)
...
sys_mmap2:
...
ENDPROC(sys_mmap2)
...
// @file: linux-6.5.13/arch/arm/kernel/entry-common.S
3.2 C
(1)linux-2.6.31-
直接采用下面方式进行定义:
asmlinkage long sys_<func_name>(...)
{
...
}
具体案例详见后面mmap的定义。
(2)linux-2.6.32+
提供了如下宏来简化系统调用的定义:
#ifdef CONFIG_FTRACE_SYSCALLS
...
#define SYSCALL_DEFINE0(sname) \
SYSCALL_TRACE_ENTER_EVENT(_##sname); \
SYSCALL_TRACE_EXIT_EVENT(_##sname); \
static const struct syscall_metadata __used \
__attribute__((__aligned__(4))) \
__attribute__((section("__syscalls_metadata"))) \
__syscall_meta_##sname = { \
.name = "sys_"#sname, \
.nb_args = 0, \
.enter_event = &event_enter__##sname, \
.exit_event = &event_exit__##sname, \
}; \
asmlinkage long sys_##sname(void)
#else
#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void)
#endif
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
// @file: linux-2.6.32/include/linux/syscalls.h
上述SYSCALL_DEFINEx的定义因是否支持ftrace而异:
#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...) \
static const char *types_##sname[] = { \
__SC_STR_TDECL##x(__VA_ARGS__) \
}; \
static const char *args_##sname[] = { \
__SC_STR_ADECL##x(__VA_ARGS__) \
};