sbw*_*sbw 3 c++ windows calling-convention visual-c++
__cdecl
只是对调用约定的测试。
这是一个 cmake 项目,只有 1 个源文件:
#include <stdio.h>
#define CALL_CONVENTION __cdecl
void CALL_CONVENTION f(int a, int b)
{
printf("%d, %d", a, b);
}
int main()
{
f(1, 2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用来set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /FA")
输出汇编代码。
当我使用 构建时cmake -G "Visual Studio 15"
,它构建了一个 32 位应用程序,并且一切都在预期中:
...
; Line 12
push ebp
mov ebp, esp
; Line 13
push 2 ; <------- argument 2
push 1 ; <------- argument 1
call _f ; <------- call function
add esp, 8
; Line 15
xor eax, eax
; Line 16
cmp ebp, esp
call __RTC_CheckEsp
pop ebp
ret 0
_main ENDP
...
Run Code Online (Sandbox Code Playgroud)
您可以看到参数push 2
和push 1
指令被传递,这是__cdecl
调用约定。
但如果我用来cmake -G "Visual Studio 15 Win64"
构建 64 位应用程序,__cdecl
注释似乎不起作用(参数不是通过堆栈传递的):
...
; Line 12
$LN3:
push rdi
sub rsp, 32 ; 00000020H
mov rdi, rsp
mov ecx, 8
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 13
mov edx, 2 ; <------ argument 2
mov ecx, 1 ; <------ argument 1
call f ; <------ call function
; Line 15
xor eax, eax
; Line 16
add rsp, 32 ; 00000020H
pop rdi
ret 0
main ENDP
...
Run Code Online (Sandbox Code Playgroud)
参数通过寄存器传递,edx
而ecx
不是通过堆栈传递。
那么,为什么即使我指定,参数在 x64 中也不通过堆栈传递__cdecl
,如果我想在 x64 环境中执行相同的操作,我应该做什么。
x64 有它自己的调用约定。
\n\n\n\n\n\n\n在 ARM 和 x64 处理器上,__cdecl 被接受,但通常被编译器忽略。按照 ARM 和 x64 上的约定,如果可能,参数将在寄存器中传递,后续参数将在堆栈上传递。在 x64 代码中,使用 __cdecl 覆盖 /Gv 编译器选项并使用默认的 x64 调用约定。
\n
Microsoft docs x64 calling convention
\n\n\n默认情况下,x64 应用程序二进制接口 (ABI) 使用四寄存器快速调用约定。在调用堆栈上分配空间作为被调用者保存这些寄存器的影子存储。函数调用的参数与用于这些参数的寄存器之间存在严格的一一对应关系。任何不适合 8 个字节或不是 1、2、4 或 8 个字节的参数都必须通过引用传递。
\n\n...
\n\n整数参数在寄存器 RCX、RDX、R8 和 R9 中传递
\n
您可以看到它使用 ECX 和 EDX 来表示int a
(int b
因为它们是 32 位,而完整的 RCX 和 RDX 是 64 位)。
__stdcall
,__fastcall
并且__thiscall
也被忽略。__vectorcall
可用(/Gv 开关使其成为默认值),并且是另一种寄存器调用约定,但与 x64 默认值相比,它可以在更多情况下使用寄存器,并且有一些其他规则差异。
归档时间: |
|
查看次数: |
2075 次 |
最近记录: |