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
寄存器的值。
本文作者:上山砍大树
本文链接:https://www.cnblogs.com/shangshankandashu/p/18544070
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步