x64汇编笔记记录
0x0 前言
笔记学习会持续更新
0x1 学习(1)
对32位寄存器的写操作(包括运算结果),对相应的64位寄存器的高32位清0
立即数的使用,优先使用32位扩展,64位立即数指令较少
内存优先使用相对偏移寻址,直接寻址指令较少
0x2 调用约定
__cdecl的特点
__cdecl 是 C Declaration 的缩写,表示 C 和 C++ 默认的函数调用约定。是C/C++和MFCX的默认调用约定。
按从右至左的顺序压参数入栈。
由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的,返回值在EAX中。因此对于像printf这样可变参数的函数必须用这种约定。
编译器在编译的时候对这种调用规则的函数生成修饰名的时候,在输出函数名前加上一个下划线前缀,格式为_function。如函数int add(int a, int b)的修饰名是_add
__stdcall的特点
__stdcall是Standard Call的缩写,是C++的标准调用方式
按从右至左的顺序压参数入栈。
由被调用者把参数弹出栈。切记:函数自己在退出时清空堆栈,返回值在EAX中。
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_function@number。如函数int sub(int a, int b)的修饰名是_sub@8
__fastcall的特点
__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的。
实际上__fastcall用ECX和EDX传送前两个DWORD或更小的参数,剩下的参数仍自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。
__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@number,如double multi(double a, double b)的修饰名是@multi@16。
__fastcall和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第1个参数进ECX,第2个进EDX,其他参数是从右向左的入栈,返回仍然通过EAX
0x3 笔记(2)
x64 只有一种调用约定,__cdecl,另外两种修饰被编译器忽略代码中也不会报错(为了兼容)
调用方分配和清理参数所用的栈空间(外平栈)
前4个参数使用 rcx,rdx,r8,r9 传递
即使是寄存器传参,也要分配参数栈空间
易变寄存器:rax,rcx,rdx,r8,r9,r10,r11
push,pop 指令仅用来保存非易变寄存器,其他栈指针操作显示写寄存器rsp实现
进入call之前rsp满足0x10字节对齐
通常不使用rbp寻址栈内存,所以rsp在函数帧中尽量保持稳定(一次性分配局部变量和参数空间)