ARM64系统中兼容系统调用表compat_sys_call_table的定义和初始化

在我使用的某国产ARM64笔记本上(安装的统信UOS系统), Linux内核有2个系统调用表sys_call_tablecompat_sys_call_table

其中sys_call_table为原生64位程序使用, 而compat_sys_call_table是为了在ARM64中兼容32位ARM应用程序而实现的

今天我们简单研究下这个兼容的系统调用表compat_sys_call_table是如何定义和初始化的

compat_sys_call_table的定义在/arch/arm64/kernel/sys32.c中:

#undef __SYSCALL
#define __SYSCALL(nr, sym)  asmlinkage long __arm64_##sym(const struct pt_regs *);
#include <asm/unistd32.h>

#undef __SYSCALL
#define __SYSCALL(nr, sym)  [nr] = __arm64_##sym,

const syscall_fn_t compat_sys_call_table[__NR_compat_syscalls] = {
    [0 ... __NR_compat_syscalls - 1] = __arm64_sys_ni_syscall,
#include <asm/unistd32.h>
};

这里的关键是出现了2次的#include <asm/unistd32.h>, 其中的部分定义如下, 为了方便理解我删除了一些代码

...
#define __NR_write 4
__SYSCALL(__NR_write, sys_write)
#define __NR_open 5
__SYSCALL(__NR_open, compat_sys_open)
...
#define __NR_ftruncate64 194
__SYSCALL(__NR_ftruncate64, compat_sys_aarch32_ftruncate64)

可以看到这里就是简单调用了__SYSCALL宏, 所以:

  • 第1次#include <asm/unistd32.h>声明了所有系统调用的函数原型
  • 第2次#include <asm/unistd32.h>完成了对系统调用表compat_sys_call_table的初始化, 即把上面声明的函数赋值给系统调用表相应的项

值得注意的是这些系统调用的名字

  • 有些和传统的系统调用名字一样, 没有compat_的前缀, 说明这些系统调用和ARM64的一样, 可以直接使用ARM64实现好的
  • 有些有compat_前缀, 这说明这些系统调用需要额外实现, 并且其他已经实现好了, 我们直接使用即可, 例如上面的compat_sys_open已经在/fs/open.c中实现了
  • 有些有compat_sys_aarch32_前缀, 这些是需要我们自己实现的, 例如aarch32_ftruncate64/arch/arm64/kernel/sys32.c中实现

参考资料
https://elixir.bootlin.com/linux/v4.19.274/source/arch/arm64/kernel/sys32.c#L143
https://elixir.bootlin.com/linux/v4.19.274/source/arch/arm64/include/asm/unistd32.h#L21
https://elixir.bootlin.com/linux/v4.19.274/source/arch/arm64/include/asm/syscall_wrapper.h#L18
https://elixir.bootlin.com/linux/v4.19.274/source/fs/open.c#L1129

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容