rust - Why rust use rsi to pass parameter to fn pointer
问题描述
For normal functions, rust behaves the same as x86-64 abi which pass parameter use register starting with rdi, but for fn pointer rust use rsi, so why do rustc choose to do so?
Take this for an example
fn foo(f: fn(u64)) {
f(10);
}
fn main() {
foo(|i| {
i + 1;
});
}
the closure is compiled to
playground::main::{{closure}}:
sub rsp, 24
mov qword ptr [rsp + 8], rdi
mov qword ptr [rsp + 16], rsi
add rsi, 1
setb al
test al, 1
jne .LBB11_2
add rsp, 24
ret
and it's using rsi while the normal function foo
is compiled to
playground::foo:
sub rsp, 24
mov qword ptr [rsp + 16], rdi
mov eax, 10
mov qword ptr [rsp + 8], rdi
mov rdi, rax
mov rax, qword ptr [rsp + 8]
call rax
add rsp, 24
ret
which use rdi and calling it in main
is
lea rdi, [rip + core::ops::function::FnOnce::call_once]
call playground::foo
so this is done with calling core::ops::function::FnOnce::call_once
which does
core::ops::function::FnOnce::call_once:
sub rsp, 40
mov qword ptr [rsp + 16], rdi
mov rsi, qword ptr [rsp + 16]
lea rdi, [rsp + 8]
call playground::main::{{closure}}
jmp .LBB4_1
.LBB4_1:
jmp .LBB4_2
.LBB4_2:
add rsp, 40
ret
解决方案
Pure speculation, but it may be that closures are always compiled as structs with an inherent method which takes &self, and then a wrapper is generated to convert that to function pointer. This would allow the inherent method to also be called as a trait object where a data pointer is passed. The argument to the wrapper is passed in rdi, which then allocates stack space to store a synthesized zero size struct. That wrapper then passes the synthesized struct in rdi, and the parameter in the next parameter slot rsi. In optimized code it would be expected for the inherent method to be inlined into the wrapper, and the weird dance with the registers to synthesize a useless parameter would be eliminated.
In short it is the normal system v calling convention, but there is an extra implicit parameter that is never read, so all the actual parameters get shifted one register further along the list from normal.
推荐阅读
- blueprism - 如何删除 BluePrism 中的多个环境变量?
- python - 如何在 Maya python 中获取父关节组
- java - 如何从字符串中找到锚链接?
- protractor - 在量角器中验证标题的文本
- spring - RequestBody 传递的 MultiparFile 为空
- jenkins - 如何从 GitHub Web-Hooks 向 Jenkins 发送大于 25MB 的有效负载
- android - 在 MacOs High Sierra 中下载 SDK 工具时出错
- java - JUnit - 模拟服务嵌套映射器
- mysql - SQL获取过去24小时内每小时插入的记录数
- vue.js - VueJS:使用 v-html 来 appendChild 不起作用,为什么?