以linux 4.19作为开发参考
arm相关的系统调用表:
linux-4.19.291\arch\arm\tools\syscall.tbl
#
# Linux system call numbers and entry vectors
#
# The format is:
# <num> <abi> <name> [<entry point> [<oabi compat entry point>]]
#
# Where abi is:
# common - for system calls shared between oabi and eabi (may have compat)
# oabi - for oabi-only system calls (may have compat)
# eabi - for eabi-only system calls
#
# For each syscall number, "common" is mutually exclusive with oabi and eabi
#
0 common restart_syscall sys_restart_syscall
1 common exit sys_exit
2 common fork sys_fork
3 common read sys_read
4 common write sys_write
5 common open sys_open
6 common close sys_close
# 7 was sys_waitpid
8 common creat sys_creat
9 common link sys_link
格式说明
每一行定义一个系统调用,格式如下:
<num> <abi> <name> [<entry point> [<oabi compat entry point>]]
- <num>: 系统调用编号,这是一个唯一的整数标识符。
- <abi>: 应用二进制接口类型,表示该系统调用适用于哪种 ABI。
common
: 适用于 OABI 和 EABI 共享的系统调用(可能有兼容入口点)。oabi
: 仅适用于 OABI 的系统调用(可能有兼容入口点)。eabi
: 仅适用于 EABI 的系统调用。
- <name>: 系统调用名称。
- <entry point>: 入口点函数的名称,即实现该系统调用的内核函数。
- <oabi compat entry point>: (可选)用于 OABI 兼容的入口点函数。
示例解释
让我们逐行解释示例中的系统调用:
restart_syscall
0 common restart_syscall sys_restart_syscall
- 0: 系统调用编号为 0。
- common: 适用于 OABI 和 EABI。
- restart_syscall: 系统调用名称。
- sys_restart_syscall: 内核中的入口点函数。
mmap
mmap
是一个常见的系统调用,用于将文件或设备映射到内存地址空间。它的定义如下:
syscall.tbl: 90 oabi mmap sys_old_mmap
用户空间调用:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
内核空间:
struct mmap_arg_struct {
unsigned long addr;
unsigned long len;
unsigned long prot;
unsigned long flags;
unsigned long fd;
unsigned long offset;
};
SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg)
- addr: 指定映射的起始地址,通常为 0 表示由内核选择,也可以指定固定地址
- len: 映射的长度。
- prot: 映射区域的保护标志,如读、写、执行权限。PROT_READ | PROT_WRITE
- flags: 映射的类型和选项,如共享、私有等。MAP_SHARED
- fd: 文件描述符,表示要映射的文件。
- off: 文件偏移量,表示从文件的哪个位置开始映射。
prot:
#define PROT_READ 0x1 /* page can be read */
#define PROT_WRITE 0x2 /* page can be written */
#define PROT_EXEC 0x4 /* page can be executed */
#define PROT_SEM 0x8 /* page may be used for atomic ops */
#define PROT_NONE 0x0 /* page can not be accessed */
#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
flags
#define MAP_SHARED 0x01 /* Share changes */
#define MAP_PRIVATE 0x02 /* Changes are private */
#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
#define MAP_TYPE 0x0f /* Mask for type of mapping */
#define MAP_FIXED 0x10 /* Interpret addr exactly */
#define MAP_ANONYMOUS 0x20 /* don't use a file */
#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
# define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */
#else
# define MAP_UNINITIALIZED 0x0 /* Don't support this flag */
#endif
#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define MAP_LOCKED 0x2000 /* pages are locked */
#define MAP_NORESERVE 0x4000 /* don't check for reservations */
#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
#define MAP_NONBLOCK 0x10000 /* do not block on IO */
#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
#define MAP_SYNC 0x80000 /* perform synchronous page faults for the mapping */
ABI
OABI(Old ABI)和 EABI(Embedded ABI)是 Linux 内核中的两种应用二进制接口。它们的主要区别在于对于系统调用的参数和返回值的传递方式不同。
OABI
OABI 是 Linux 内核早期使用的应用二进制接口,它使用 ARM 标准的寄存器传递约定(ATPCS)将系统调用的参数传递给内核。OABI 的系统调用编号和参数传递方式在 ARMv4 和 ARMv5 架构上被广泛使用。
EABI
EABI 是 Linux 内核现代化的应用二进制接口,它使用基于堆栈的参数传递约定(AAPCS)将系统调用的参数传递给内核。EABI 的系统调用编号和参数传递方式在 ARMv6 架构及其之后的版本上得到了广泛采用。
区别
OABI 和 EABI 的主要区别在于系统调用的参数和返回值的传递方式。具体来说,OABI 使用寄存器来传递参数,而 EABI 使用堆栈来传递参数。这种差异导致了在不同 ABI 上编译的应用程序之间不兼容的情况。