您的特定用例可以简单地完成,如下所示:
__attribute__((naked))
void syscall_create_thread(void (*f) (void *), void * args, unsigned int arg_size)
{
asm("mov r7, #" TOSTRING(SYSCALL_ID_CREATE_THREAD) :::"r7");
asm("SVC #0");
asm("RET");
}
这依赖于这样一个事实,即架构的调用约定定义了传递给函数的参数被放置在寄存器中
r0, r1...
由呼叫者。当你制作函数时
naked
您告诉编译器不要为函数生成任何序言/结语,也就是说不要创建堆栈帧、保存被调用者保存的寄存器,甚至添加
ret
指令。但这意味着你也需要格外小心,自己添加缺失的部分。
以下是最后一个示例代码和生成的程序集,以说服您它是有效的:
#include <stdlib.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define SYSCALL_ID_CREATE_THREAD 2
__attribute__((naked))
void syscall_create_thread(void (*f) (void *), void * args, unsigned int arg_size)
{
asm("mov r7, #" TOSTRING(SYSCALL_ID_CREATE_THREAD) :::"r7");
asm("SVC #0");
asm("RET");
}
void callback(void* args)
{
return;
}
void caller() {
int arg = 8;
syscall_create_thread(callback, &arg, sizeof (int));
}
生成的程序集(由我注释):
callback:
bx lr
syscall_create_thread:
mov r7, #2
SVC #0
RET
caller:
str lr, [sp, #-4]!
sub sp, sp, #12
mov r3, #8
str r3, [sp, #4]
mov r2, #4 // r2=sizeof(int)
add r1, sp, r2 // r1 = address of the local `arg` variable
ldr r0, .L5 // r0 = address of callback function
bl syscall_create_thread
add sp, sp, #12
ldr lr, [sp], #4
bx lr
.L5:
.word callback
看看这个
Godbolt
编辑:
显然,当函数“裸”时
r7
被标记为clobbered,因此它不会像应该的那样“被调用者保存”,因此需要对上述代码进行一些修改,以确保
r7
值在中保存和恢复
syscall_create_thread()
功能。最简单的方法是在非被调用者保存的寄存器中执行此操作,例如
r3
或
r4
。或者可以在堆栈上完成。