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



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

void execute_system_call(short value, const int *arguments, int argument_count) {
// TODO: Use arguments
asm volatile (
"li 0, %0nt"
"scnt"
:
: "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, %0nt"
"scnt"
:
: "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, %0nt"
"scnt"
:
: "r"(value)
);
}

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

因此,我们可能想要mr("移动寄存器")而不是li:

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

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

然而,它还没有完全完成。由于系统调用可能会返回一些内容,因此还需要在内联asm的输出约束中进行描述。返回值的存储方式将取决于您所使用的系统的ABI。

此外,根据您的系统调用ABI,sc指令可能会更改其他寄存器和/或内存。您还需要在asm语句的clobber constraints中列出这些内容。

然后,我们有了输入参数。这一点的实际实现将真正取决于程序的函数调用ABI和主管代码的系统调用ABI。

如果这些非常相似,您可能会发现将execute_system_call实现为实际ASM要比将其实现为带内联ASM的C要容易得多。这样,您就不必将参数从C解压缩到内联ASM。否则,您将需要创建类似的代码来将arguments数组的元素放入特定的寄存器中。

作为健全性检查,您的平台是否不提供syscall功能?这听起来正是你想要的。

最新更新