开发环境配置
; 动态链接:; 动态链接CRTincludelib ucrt.libincludelib vcruntime.libincludelib msvcrt.lib; 兼容stdio符号includelib legacy_stdio_definitions.lib
extern printf :proc
.constszText db "Hello World", 0
.codemain proc sub rsp, 28h mov rcx, offset szText call printf add rsp, 28h xor eax,eax retmain endpend
ucrt.lib
和vcruntime.lib
构成完整的现代VS CRT
。使用legacy_stdio_definitions.lib
添加兼容的stdio
符号。
x64寄存器

注意
mov rax, -1xor eax, eax ; 使用32位寄存器,会将rax的高32位扩展为0 ; 此时rax的高32位变为了0
xor al, al; 使用非32位寄存器,不会拓展
x64 ABI约定
栈对齐

每一个函数都保证自身的栈对齐到16。那么当函数内部使用call
指令后,为了保存返回地址8字节
,此时进入被调用函数时,被调用函数的栈未对齐到16
。

调用约定
windows x64
仅使用__vectorcall
一种调用约定,前四个参数使用rcx
、rdx
、r8
、r9
进行传递,多余参数使用栈传递。
如果传递的是浮点类型,那么将会使用XMM0
-XMM3
四个寄存器进行传递
整数参数在寄存器 RCX、RDX、R8 和 R9 中传递。 浮点数参数在 XMM0L、XMM1L、XMM2L 和 XMM3L 中传递。
隐藏的
this
指针被视为第一个整数类型参数。 当前四个自变量之一中的 HVA 自变量无法传入可用寄存器时,对调用方分配的内存的引用将传入相应的整数类型寄存器。 第四参数位置之后的整数类型参数在堆栈上传递。
如果混合,则按照固定顺序传递
func3(int a, double b, int c, float d, int e, float f);// a in RCX, b in XMM1, c in R8, d in XMM3, f then e pushed on stack
上面的例子中,rdx
和XMM2
寄存器未使用。
返回值
整形使用RAX
,浮点类型使用XMM0
可以适应 64 位的标量返回值(包括
__m64
类型)是通过 RAX 返回的。 非标量类型(包括浮点类型、双精度类型和向量类型,例如__m128
、__m128i
、__m128d
)以 XMM0 的形式返回。 返回到 RAX 或 XMM0 中的值的未使用位数的状态未定义。
影子存储
如果我们的函数中存在调用其他函数,那么就必须分配20h
(32
)字节的大小空间来供系统使用影子存储。
为了兼容变参传递,所以变参函数的内部从影子存储读取参数后,再进行栈的遍历。

便捷的结构
main proc sub rsp, 20h ; 影子空间抬栈 sub rsp, 50h ; 为传参预留10个qword 第一个栈中参数为 [rsp+20h] sub rsp, 0F8h ; 为局部变量预留空间,第一个局部变量为 [rsp+78h]开始
add rsp, 20h add rsp, 50h add rsp, 0F8h retmain endp