x64 参数和 return 值调用约定
x64 argument and return value calling convention
我使用 -Os -march=haswell
调用 Clang 12.0.0 来编译以下 C 程序:
int bar(int);
int foo(int x) {
const int b = bar(x);
if (x || b) {
return 123;
}
return 456;
}
生成以下程序集:
foo: # @foo
push rbx
mov ebx, edi
call bar
or eax, ebx
mov ecx, 456
mov eax, 123
cmove eax, ecx
pop rbx
ret
https://gcc.godbolt.org/z/WsGoM56Ez
据我了解,foo 的调用者在 RAX/EAX 中设置了 x。 foo 然后调用 bar,它不需要修改 RAX/EAX,因为 x 作为未修改的输入传递。
or eax, ebx
指令似乎将输入 x 与 bar 的结果进行比较。这个结果如何最终出现在 EBX 中? mov ebx,edi
有什么作用?
恐怕你误会了:
- 根据 x86-64 System V calling convention.
,函数参数在 rdi 中传递
- 注册 rbx must not be modified by a function; GCC saves/restores 根据需要,它可以在
bar
. 的调用中保留 x
的副本
- 函数 return 值在 rax 中。 (其实eax;一个32位的
int
只用了低半)
您可以通过编译类似 int foo(int x){return x;}
的函数来验证基础知识 - 您只会看到 mov eax, edi
.
这里是评论版本:
foo: # @foo
push rbx # save register rbx
mov ebx, edi # save argument `x` in ebx
call bar # a = bar() (in eax)
or eax, ebx # compute `x | a`, setting FLAGS
mov ecx, 456 # prepare 456 for conditional move
mov eax, 123 # eax = 123
cmove eax, ecx # if `(x | a) == 0` set eax to 456
pop rbx # restore register rbx
ret # return value is in eax
编译器将 x || b
优化为 (x | b) != 0
,允许无分支代码生成。
请注意,与大多数整数 ALU 指令不同,mov
不会修改 FLAGS。
我使用 -Os -march=haswell
调用 Clang 12.0.0 来编译以下 C 程序:
int bar(int);
int foo(int x) {
const int b = bar(x);
if (x || b) {
return 123;
}
return 456;
}
生成以下程序集:
foo: # @foo
push rbx
mov ebx, edi
call bar
or eax, ebx
mov ecx, 456
mov eax, 123
cmove eax, ecx
pop rbx
ret
https://gcc.godbolt.org/z/WsGoM56Ez
据我了解,foo 的调用者在 RAX/EAX 中设置了 x。 foo 然后调用 bar,它不需要修改 RAX/EAX,因为 x 作为未修改的输入传递。
or eax, ebx
指令似乎将输入 x 与 bar 的结果进行比较。这个结果如何最终出现在 EBX 中? mov ebx,edi
有什么作用?
恐怕你误会了:
- 根据 x86-64 System V calling convention. ,函数参数在 rdi 中传递
- 注册 rbx must not be modified by a function; GCC saves/restores 根据需要,它可以在
bar
. 的调用中保留 - 函数 return 值在 rax 中。 (其实eax;一个32位的
int
只用了低半)
x
的副本
您可以通过编译类似 int foo(int x){return x;}
的函数来验证基础知识 - 您只会看到 mov eax, edi
.
这里是评论版本:
foo: # @foo
push rbx # save register rbx
mov ebx, edi # save argument `x` in ebx
call bar # a = bar() (in eax)
or eax, ebx # compute `x | a`, setting FLAGS
mov ecx, 456 # prepare 456 for conditional move
mov eax, 123 # eax = 123
cmove eax, ecx # if `(x | a) == 0` set eax to 456
pop rbx # restore register rbx
ret # return value is in eax
编译器将 x || b
优化为 (x | b) != 0
,允许无分支代码生成。
请注意,与大多数整数 ALU 指令不同,mov
不会修改 FLAGS。