用于在 PowerPC 中执行系统调用的通用 C/C++ 函数

Generic C/C++ function for execution system calls in PowerPC

我想编写一个 C/C++ 函数来执行一个 syscall,它将 syscall 值作为参数以及可选的附加参数。

void execute_system_call(short value, const int *arguments, int argument_count) {
    // TODO: Use arguments
    asm volatile (
    "li 0, %0\n\t"
    "sc\n\t"
    :
    : "i"(0x1337) // TODO: Use variable
    );
}

使用 C 变量作为 syscall 编译代码会导致以下编译错误(因此这已经无法按预期工作):

assembly.cpp: In function 'void execute_system_call(short int, const int*, int)':
assembly.cpp:62:3: warning: asm operand 0 probably doesn't match constraints
  );
   ^
assembly.cpp:62:3: error: impossible constraint in 'asm'
make[1]: *** [assembly.o] Error 1
make: *** [build] Error 2

此外,我还需要将参数传递到各自的寄存器中。在 PowerPC 中,这通常是 r3r4、...这看起来也很麻烦,因为我不想明确指定它并根据调用约定保留寄存器分配改为编译器。也许后者是不可能的,所以我不得不把它写得更像下面的伪代码:

lis 3, $arguments[0]@h # Load higher 16-bit
ori 3, 3, $arguments[0]@l # Load lower 16-bit
lis 4, $arguments[1]@h
ori 4, 4, $arguments[1]@l
lis 5, $arguments[2]@h
ori 5, 5, $arguments[2]@l
...
li 0, $value
sc

请注意,如果假定 argument_count 始终为8 并且不必是可变的,因此方法签名也可以是

void execute_system_call(short value, const int *arguments)

如何做到这一点?

假设您修改后的代码如下所示:

void execute_system_call(short value, const int *arguments, int argument_count) {
    // TODO: Use arguments
    asm volatile (
    "li 0, %0\n\t"
    "sc\n\t"
    :
    : "i"(value)
    );
}

- 然后你要求 gcc 将 value 变量作为立即变量传递(因为你仍在使用 "i" 作为约束)。由于 value 是一个变量,而不是立即数,因此这将不起作用,这就是您在那里看到的错误的原因。

相反,您需要使用 "r" 输入约束来引用寄存器值:

void execute_system_call(short value, const int *arguments, int argument_count) {
    // TODO: Use arguments
    asm volatile (
    "li 0, %0\n\t"
    "sc\n\t"
    :
    : "r"(value)
    );
}

- 但这次,约束是正确的,但程序集不是 - li 需要一个寄存器和一个立即数,但我们需要两个寄存器。

所以,我们可能想要 mr ("move register") 而不是 li:

void execute_system_call(short value, const int *arguments, int argument_count) {
    // TODO: Use arguments
    asm volatile (
    "mr 0, %0\n\t"
    "sc\n\t"
    :
    : "r"(value)
    );
}

这应该执行 sc 指令,其中 r0 包含 value

然而,它还没有完全完成。由于您的系统调用可能 returns 一些东西,您还需要在内联 asm 的输出约束中描述它。 return 值的存储方式将取决于您正在使用的系统的 ABI。

另外,根据您的系统调用 ABI,sc 指令可能会改变其他寄存器,and/or 内存。您还需要在 asm 语句的 clobber constriants 中列出那些。

然后,我们有了输入参数。这个的实际实现将取决于你程序的函数调用 ABI,以及主管代码的系统调用 ABI。

如果这些非常相似,您可能会发现将 execute_system_call 实现为实际的 ASM 而不是 C-with-inline-ASM 更容易。这样,您不必将参数从 C 解包到内联 ASM。否则,您将需要创建类似的代码来将 arguments 数组的元素放入特定的寄存器中。

作为完整性检查,您的平台不提供 syscall 功能吗?这听起来正是您在这里寻找的东西。