X64调用约定

fastcall

在64位下只有一种调用约定,类似于fastcall,要写其他的也不会出错,这主要是为了兼容以前定义的32的头文件。

前4个参数使用 rcx rdx r8 r9传递

写一个没有参数没有返回值的函数反汇编如下,可以看出不再像32位一样push ebp mov ebp,esp.
而是只保存了rdi就推出了。
在这里插入图片描述
1个参数
一个参数的情况下采用ecx传参
在这里插入图片描述
参数大于32位采用rcx传参
在这里插入图片描述

函数里面把参数复制到了rsp+8
在这里插入图片描述

4个参数的情况
参数采用ecx,edx,r8d,r9d
在这里插入图片描述
参数大于32位采用的是rcx,rdx,r8,r9寄存器
在这里插入图片描述

在函数里,把参数复制到rsp+0x20 +0x18 +0x10 +0x8的位置
在这里插入图片描述

大于4个参数的情况
传参多了一个rsp+0x20内存.加上call对esp+8的位置,实际在函数里这个内存地址是rsp+0x28。

在这里插入图片描述

寄存器传参也要分配栈

首先看一下没有调用函数时提升的栈空间是0x10
在这里插入图片描述
调用一个没有参数的函数,栈空间提升了0x10. 这是给函数的返回地址和多给了8字节的栈空间。
这8字节是给函数内部保存寄存器参数的值的。mov [rsp+8],rcx
在这里插入图片描述

易变寄存器和非异变寄存器操作

异变寄存器:rax rcx rdx r8 r9 r10 r11 其余为非异变寄存器
push pop指令仅用来保存非易变寄存器。
意思是如果要在自己的汇编代码里使用非异变寄存器需要先保存
从一个空的函数里面就可以看出来。
在这里插入图片描述

汇编调用函数的问题

即使函数只有一个参数,也得分配0x20的栈空间 sub rsp,0x20

在这里插入图片描述

通常不使用rbp寻址栈内存,所以rsp在函数中尽量保持稳定(一次性分配参数和变量空间)
如下图:连续调用4次函数,并没有像32位那样add esp,xxx
而是直接在函数main函数头部sub rsp,0x20 ,在尾部add sup,0x20
对于调用的函数参数少于4个字节的情况下栈空间就够了。多余4个会分配更多空间。
在这里插入图片描述
像下面这样其中有一个函数的参数是5个会出现什么情况呢?
可以看出现在是sub rsp,0x30 也就是说编译器并不是按照最多参数5个分配0x28而是对其了0x10。
直接分配的0x30字节
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41490873/article/details/108861178