5.1.3 内核层:ARM64 Linux系统调用的定义

5.1. ARM64 Linux系统调用

5.1.1 用户层:用hello world演示系统调用

5.1.2 内核层:ARM64 Linux系统调用的流程

5.1.3 内核层:ARM64 Linux系统调用的定义

在上文中,以hello world程序使用的系统调用write为例,根据内核层的调用堆栈,其对应的syscall_fn就是__arm64_sys_write。

__arm64_sys_write是如何定义的?

又是如何插入sys_call_table的呢? 

第一问:__arm64_sys_write是如何定义的?

是在fs/read_write.c中使用SYSCALL_DEFINE3宏来进行定义的,即上图中的第608行。

如上图所示,SYSCALL_DEFINE3宏,定义在include/linx/syscalls.h,数字3代表所定义的函数有3个入参。SYSCALL_DEFINE3依赖于其它宏定义,关键依赖关系是:SYSCALL_DEFINE3->SYSCALL_DEFINEx->__SYSCALL_DEFINEx。其中最后一个__SYSCALL_DEFINEx宏,如果沿着图中的箭头去展开,那么write的系统调用函数是第239行定义的sys_write,并不是上图实际调用堆栈显示的__arm64_sys_wrirte。

为什么?

同样是在include/linx/syscalls.h中更靠前的地方,如果定义了CONFIG_ARCH_HAS_SYSCALL_WRAPPER,则包含asm/syscall_wrapper.h头文件。

asm/syscall_wrapper.h头文件会提前定义__SYSCALL_DEFINEx,如果下图第47行。针对write的系统调用函数进行展开,就是__arm64_sys_write。这个宏定义很复杂,实际定义了3个函数,调用关系是__arm64_sys_write->__se_sys_write->__do_sys_write,与上面的调用堆栈完全匹配。

第二问:__arm64_sys_write是如何插入sys_call_table的呢?

回到sys_call_table定义的地方arch/arm64/kernel/sys.c。

第69行,定义了函数指针数组sys_call_table,且数组的大小为__NR_syscalls。

第70行,把所有的数组元素都初始化为__arm64_sys_ni_syscall函数,这个函数是一个通用的系统调用处理函数,当系统调用号无效或未实现时,它会被调用。

第71行,包含了一个头文件<asm/unistd.h>,它会使用第67行定义的__SYSCALL宏来初始化数组的元素! 头文件包含是非常复杂的,展开过程如下:

arch/arm64/kernel/sys.c

->#include <asm/unistd.h>即arch/arm64/include/asm/unistd.h

->#include <uapi/asm/unistd.h>即arch/arm64/include/uapi/asm/unistd.h

->#include <asm-generic/unistd.h>即include/asm-generic/unistd.h

->#include <uapi/asm-generic/unistd.h>即include/uapi/asm-generic/unistd.h

第205行,定义了write系统调用号为64。同时可以看到,所有系统调用号都是在include/uapi/asm-generic/unistd.h文件中定义的。

第206行,展开后为”[64] = __arm64_sys_write, “,注意最后有个逗号,因为这是嵌入在sys_call_table数组的定义中的。

总结一下,本章节以系统调用write为例,追踪系统调用发生的顺序,找到系统调用表sys_call_table中的__arm64_sys_write。__arm64_sys_write是如何定义的?又是如何插入sys_call_table的呢?通过解答上述两个问题,彻底搞清楚了arm64系统调用的原理。

ARM64 Linux

位置与定义

系统调用号

include/uapi/asm-generic/unistd.h:

#define __NR_write 64

系统调用表

arch/arm64/kernel/sys.c:

const syscall_fn_t sys_call_table[__NR_syscalls] = {

[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall,

#include <asm/unistd.h>

};

系统调用函数

fs/read_write.c:

SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,

        size_t, count)

系统调用号和系统调用函数插入系统调用表

include/uapi/asm-generic/unistd.h:

__SYSCALL(__NR_write, sys_write)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值