syscall
syscall
分析_syscall_的相关参数:
intptr_t _syscall_(intptr_t type, intptr_t a0, intptr_t a1, intptr_t a2) {
register intptr_t _gpr1 asm (GPR1) = type;
register intptr_t _gpr2 asm (GPR2) = a0;
register intptr_t _gpr3 asm (GPR3) = a1;
register intptr_t _gpr4 asm (GPR4) = a2;
register intptr_t ret asm (GPRx);
asm volatile (SYSCALL : "=r" (ret) : "r"(_gpr1), "r"(_gpr2), "r"(_gpr3), "r"(_gpr4));
return ret;
}
其相关的宏定义为
// helper macros
#define _concat(x, y) x ## y
#define concat(x, y) _concat(x, y)
#define _args(n, list) concat(_arg, n) list
#define _arg0(a0, ...) a0
#define _arg1(a0, a1, ...) a1
#define _arg2(a0, a1, a2, ...) a2
#define _arg3(a0, a1, a2, a3, ...) a3
#define _arg4(a0, a1, a2, a3, a4, ...) a4
#define _arg5(a0, a1, a2, a3, a4, a5, ...) a5
// extract an argument from the macro array
#define SYSCALL _args(0, ARGS_ARRAY)
#define GPR1 _args(1, ARGS_ARRAY)
#define GPR2 _args(2, ARGS_ARRAY)
#define GPR3 _args(3, ARGS_ARRAY)
#define GPR4 _args(4, ARGS_ARRAY)
#define GPRx _args(5, ARGS_ARRAY)
# define ARGS_ARRAY ("ecall", "a7", "a0", "a1", "a2", "a0")
首先从GPR1开始拆解宏定义。
GPR1 -> _args(1, ARGS_ARRAY)
_args(1, ARGS_ARRAY) -> _arg1 ARGS_ARRAY
_arg1(ARGS_ARRAY) -> a7
其他拆解同理,拆解完毕后分析内联汇编语法。
intptr_t _syscall_(intptr_t type, intptr_t a0, intptr_t a1, intptr_t a2) {
register intptr_t _gpr1 asm ("a7") = type;
register intptr_t _gpr2 asm ("a0") = a0;
register intptr_t _gpr3 asm ("a1") = a1;
register intptr_t _gpr4 asm ("a2") = a2;
register intptr_t ret asm ("a0");
asm volatile ("ecall" : "=r" (ret) : "r"(_gpr1), "r"(_gpr2), "r"(_gpr3), "r"(_gpr4));
return ret;
}
例如
register intptr_t _gpr1 asm ("a7") = type;
register:C 语言的一个关键字,表示该变量建议存储在 CPU 寄存器中,而不是内存中。_gpr1:这是声明的变量名asm (GPR1):将 C 变量_gpr1与汇编寄存器a7绑定起来。这样编译器会将该_gpr1的值加载到a7寄存器中.= type;:这部分是变量_gpr1的初始化,_gpr1被初始化为type的值。
这行代码包含的关键意思就是将变量_gpr1与寄存器a7连接起来。
最后
asm volatile ("ecall" : "=r" (ret) : "r"(_gpr1), "r"(_gpr2), "r"(_gpr3), "r"(_gpr4));
- 输出操作数(
: "=r" (ret))=r是一个输出操作数约束符,告诉编译器,输出操作数ret(存储返回值的变量)需要被存储在一个通用寄存器中。ret是一个变量,它将存储ecall执行后的返回值(即通过a0寄存器返回的值)。在执行ecall后,a0寄存器中存放的值将被复制到ret。
- 输入操作数(
: "r"(_gpr1), "r"(_gpr2), "r"(_gpr3), "r"(_gpr4))"r"表示a7、a0、a1和a2(也就是 RISC-V 的通用寄存器)_gpr1,_gpr2,_gpr3,_gpr4是用来传递给ecall的四个输入参数,分别放在寄存器a7、a0、a1和a2中
具体来说,_gpr1 会被存储到 a7 寄存器,_gpr2 会被存储到 a0 寄存器,_gpr3 会被存储到 a1 寄存器,_gpr4 会被存储到 a2 寄存器。
此时ecall执行后,ret变量将包含a0寄存器的值。

浙公网安备 33010602011771号