gpt4 book ai didi

c - Linux 上的系统调用参数类型是什么?

转载 作者:太空狗 更新时间:2023-10-29 14:57:11 25 4
gpt4 key购买 nike

我想编写一个执行系统调用的通用函数。有点像

long my_syscall2(long number, long arg1, long arg2);

我希望它尽可能便携。所有架构的实现显然不同。函数的签名是否也需要不同?我可以使用 long 还是应该使用其他东西?

以下是我找到的可能的解决方案:

  • 内核使用一些dark magic : (__SYSCALL_DEFINEx 调用 __SC_LONG 获取类型,__SC_LONG 包含魔法)。我在某处听说用户空间中的类型与内核空间中的类型并不总是相同,所以我不知道我是否可以使用它。
  • musl-libc uses long for all architectures that it supports except x32 :(在 [arch]/syscall_arch.h 中定义)。
  • 我可以找到我想要支持的所有处理器架构和编译器的文档,查找寄存器大小和整数类型大小,并选择与寄存器大小相同的任何整数类型。

所以我想问题是“是否有一些规则说‘系统调用参数的类型总是long,但有一些异常(exception),比如 x32”,或者我是否需要查找每种架构的文档和编译器?”

编辑:我知道一些系统调用将指针和其他类型作为参数。我想编写可以使用通用参数类型调用任何系统调用的通用函数。这些通用参数类型应该足够大以容纳任何实际参数类型。我知道这是可能的,因为 syscall()函数存在。

Edit2:这是此问题的另一种部分解决方案。

这些函数的实现目前看起来像这样:

static __inline long my_syscall2(long number, long arg1, long arg2)
{
unsigned long ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(number), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory");
return ret;
}

有趣的部分是 "=a"(ret),这意味着存储在寄存器 a 中的系统调用返回值应该保存到变量 ret 中。我可以编写一个宏来创建系统调用并将结果存储到调用者提供的变量中,而不是编写一个函数来创建局部变量、进行系统调用、将其返回值保存到变量中并返回变量。它看起来像这样:

#define my_syscall2(RET, NUMBER, ARG1, ARG2) \
__asm__ __volatile__ ("syscall" : "=a"(RET) : "a"(NUMBER), "D"(ARG1), "S"(ARG2) \
: "rcx", "r11", "memory");

它会像这样使用:

long result;
void * arg1;
int arg2;
my_syscall2(result, <syscall number>, arg1, arg2);

这样我就不需要知道寄存器大小和足以容纳寄存器值的整数类型。

最佳答案

系统调用参数在寄存器中传递。因此,大小限于 CPU 寄存器的大小。也就是说,32 位在 32 位架构上,64 位在 64 位架构上。 float 不能以这种方式传递给内核。传统上,内核不使用浮点指令(并且可能无法使用,因为 FPU 状态通常不会在进入内核时保存),因此尽量避免在您自己的系统调用中使用 float 。

系统调用使用较小类型的参数零或符号扩展它们。使用较大参数类型的系统调用可能会将参数拆分到多个寄存器中。

系统调用(如 mmap())有很多参数可以通过将参数作为指向结构的指针传递来实现,但这具有可测量的性能开销,因此避免设计系统调用有五个以上的参数。

归根结底,使用适合您要发送的值的类型。让 libc 处理将数据放在正确的位置。

关于c - Linux 上的系统调用参数类型是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35628927/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com