[计组] i386调用约定

i386调用约定

调用约定是由硬件的汇编指令call和ret的微指令和软件的汇编指令规范共同完成的
一般为如下顺序

  1. 父函数参数入栈(软件汇编代码)
  2. 父函数call(硬件微指令)
  3. 子函数栈建立(软件汇编代码)
  4. 子函数栈清理(软件汇编代码)
  5. 子函数ret(硬件微指令)
  6. 父函数栈清理(软件汇编代码)

下文中将演示代码 f(A1, A2, A3, A4, ..., An-1, An)a.f(A1, A2, A3, A4, ..., An-1, An) 在不同的调用约定下, 栈的变化过程
其中, 用数字表示以上的6个阶段, 其后紧接着的是该阶段结束后的栈的状态和寄存器参数的示意
"["表示栈底, 处于地址高部, 由ebp/rbp寄存器的值直接决定, 其左边紧贴着的值的地址为ebp+0/rbp+0, 每往右一个参数地址递减4/8
最右边的参数由esp/rsp寄存器的值直接决定, 其地址为esp+0/rsp+0, 每往左一个参数地址递增4/8
"_"表示任意值
call指令只有一种, 因此1到2的变化都是一样的
ret指令有两种, 一种只出栈eip, 另一种不仅出栈eip, 还令esp增加一个数(即清理栈)

x86

每个参数大小为4B

__stdcall

传参寄存器: 无

  1. [, …, An, An-1, …, A4, A3, A2, A1
  2. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  3. …, An, An-1, …, A4, A3, A2, A1, 上级eip, 上级ebp [
  4. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  5. [, …
  6. [, …

返回值寄存器: eax

__cdecl

传参寄存器: 无

  1. [, …, An, An-1, …, A4, A3, A2, A1
  2. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  3. …, An, An-1, …, A4, A3, A2, A1, 上级eip, 上级ebp [
  4. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  5. [, …, An, An-1, …, A4, A3, A2, A1
  6. [, …

返回值寄存器: eax

__fastcall

传参寄存器: edx=A2, ecx=A1

  1. [, …, An, An-1, …, A4, A3
  2. [, …, An, An-1, …, A4, A3, 上级eip
  3. …, An, An-1, …, A4, A3, 上级eip, 上级ebp [, A2, A1
  4. [, …, An, An-1, …, A4, A3, 上级eip
  5. [, …
  6. [, …

返回值寄存器: eax

__vectorcall

略(用到时再补充试验)

thiscall

传参寄存器: ecx=this

  1. [, …, An, An-1, …, A4, A3, A2, A1
  2. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  3. …, An, An-1, …, A4, A3, A2, A1, 上级eip, 上级ebp [, this
  4. [, …, An, An-1, …, A4, A3, A2, A1, 上级eip
  5. [, …
  6. [, …

返回值寄存器: eax

x64

每个参数大小为8B

__fastcall

传参寄存器: r9d=A4, r8d=A3, rdx=A2, rcx=A1

  1. [, …, An, An-1, …, A6, A5, _, _, _, _
  2. [, …, An, An-1, …, A6, A5, _, _, _, _, 上级eip
  3. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1, 上级eip
  4. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1, 上级eip
  5. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1
  6. [, …, An, An-1, …, A6, A5, _, _, _, _

返回值寄存器: eax
父函数不能假定子函数一定给A1到A4在内存中预留的空间赋了值, 故应为任意值
注: 当参数数少于4时, 依然要在调用栈留下32B的空间, 即

  1. [, …, _, _, _, _
  2. [, …, _, _, _, _, 上级eip
  3. [, …, _, A3, A2, A1, 上级eip
  4. [, …, _, A3, A2, A1, 上级eip
  5. [, …, _, A3, A2, A1
  6. [, …, _, _, _, _

__vectorcall

当参数含__m128型数据时, 使用对应的xmm寄存器传参, 同时应将调用约定改为__vectorcall
传参寄存器: r9d/xmm3=A4, r8d/xmm2=A3, rdx/xmm1=A2, rcx/xmm0=A1

  1. [, …, An, An-1, …, A6, A5, _, _, _, _
  2. [, …, An, An-1, …, A6, A5, _, _, _, _, 上级eip
  3. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1, 上级eip
  4. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1, 上级eip
  5. [, …, An, An-1, …, A6, A5, A4, A3, A2, A1
  6. [, …, An, An-1, …, A6, A5, _, _, _, _

返回值寄存器: eax/xmm0
视具体情况, 第3步可能会腾出空间在内存中暂存数据, 如
传参寄存器: r9d=A4, r8d=A3, xmm1=A2, xmm0=A1

  1. [, …, An, An-1, …, A6, A5, _, _, _, _
  2. [, …, An, An-1, …, A6, A5, _, _, _, _, 上级eip
  3. [, …, An, An-1, …, A6, A5, A4, A3, &A2, &A1, 上级eip, _, A2(高位), A2(低位), A1(高位), A1(低位)
  4. [, …, An, An-1, …, A6, A5, A4, A3, &A2, &A1, 上级eip
  5. [, …, An, An-1, …, A6, A5, A4, A3, _, _
  6. [, …, An, An-1, …, A6, A5, _, _, _, _

thiscall

传参寄存器: r9d/xmm3=a3, r8d/xmm2=a2, rdx/xmm1=a1, rcx/xmm0=this

  1. [, …, An, An-1, …, A5, A4 _, _, _, _
  2. [, …, An, An-1, …, A5, A4, _, _, _, _, 上级eip
  3. [, …, An, An-1, …, A5, A4, A3, A2, A1, this, 上级eip
  4. [, …, An, An-1, …, A5, A4, A3, A2, A1, this, 上级eip
  5. [, …, An, An-1, …, A5, A4, A3, A2, A1, this
  6. [, …, An, An-1, …, A5, A4, _, _, _, _

返回值寄存器: eax/xmm0
相当于this成了原第一个参数的__fastcall或__vectorcall

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值