汇编函数调用的传参规则
汇编函数调用的传参规则
0x01 一般流程
函数调用一般有个模板。
1 | push es |
中间的ccc…就是填充缓冲区。填充后可以用来写入局部变量。
EBP后面的高址,存有恢复用的EIP,和call函数前push的参数。
EBP前面的低址,用来存局部变量。
根据函数调用约定的不同,堆栈平衡的方式不同
如果是__cedcl约定,是在母函数中平衡堆栈,就是函数调用完返回后,在调用者里add esp,xx来平衡堆栈。
0x02 调用约定
有几种函数调用约定,不同的调用约定,参数的传递,堆栈的平衡方式不同。下面是三种常见的调用约定:
__cedcl 约定:
参数从右往左,依次入栈。堆栈平衡在母函数中完成。
在函数调用前,将参数压栈。
push xxx
push xxx
…
然后call 函数。
//函数执行完毕
add esp ,xx
//在母函数中平衡堆栈
stdcall 约定:
参数从右往左依次入栈,在子函数中 平衡堆栈。
参数还是在调用前push 入栈。
平衡堆栈时,在 ret 后加个 xx 恢复堆栈
例如 ret 0x8,相当于 pop eip add esp,0x8
fastcall 约定:
参数从右往左依次入栈,在子函数中 平衡堆栈
参数1个或者两个用 寄存器 传参,多于两个,多余两个的部分还是压栈传参。
例如 (int a,int b,int c)
push c
mov eax,b
mov ecx,a
然后再call 函数,最后在子函数中平衡堆栈。
————————————————
版权声明:本文为CSDN博主「dittozzz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43394612/article/details/84332149
0x03 64位传参
linux:
摘自:http://abcdxyzk.github.io/blog/2012/11/23/assembly-args/
当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。
当参数为7个以上时, 前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。
参数个数大于 7 个的时候:
1 | H(a, b, c, d, e, f, g, h); |
附64位寄存器表:
windows:
摘抄:https://www.cnblogs.com/iBinary/p/10959444.html
x64调用示例:
1 | sub rsp,0x28 |
传参方式:
首先说明一下,在X64下,是寄存器传参. 前4个参数分别是 rcx rdx r8 r9进行传参.多余的通过栈传参.从右向左入栈
申请参数预留空间:
在x64下,在调用一个函数的时候,会申请一个参数预留空间.用来保存我们的参数.比如以前我们通过push压栈
参数的值.相应的栈就会抬高.其实x64下,一样会申请.只不过这个地方在进函数的时候并没有值.进入函数之后才会将寄存器的值在拷贝到这个栈中.其实就相当于你还是push了.只不过我是外边申请空间,内部进行赋值。
如下:
1 | sub rsp,0x28 //申请的栈空间为0x28,就相当于我们push rcx rdx r8 r9.只不过只是申请. |
总结:
- 在调用函数之前,会申请参数预留空间.(rcx,rdx,r8,r9)
- 函数内部,会将寄存器传参的值(rcx,rdx,r8,r9)保存到我们申请的预留空间中.
上面这两步其实就相当于x86下的 push r9 push r8 push rdx,push rcx - 调用约定是__fastcall.传参有rcx rdx,平栈是按照c调用约定平栈. 也就是调用者平栈.