x86参数传递规则

1.函数调用者必须在ccallee返回之后清理堆栈。

2.每个函数拥有固定数量的参数,这意味着被调用函数可以在一个地方对参数进行清理,即在被调用函数内部进行堆栈参数的清理,而不是分散在每一次调用该函数的代码中。

3.以下是调用过程:              

1)将参数从右到左压入堆栈:

参数从右到左依次压入堆栈,每次压入一个。调用者(caller)必须明确有多少Byte的参数,以便函数返回后清理掉。           

2)调用函数: 

处理器将下一条指令的EIP(即函数返回值)内容压入堆栈,同时EIP设置成被调函数的地址。这步完成之后,控制权交给Callee。到此时为止,%EBP不发生任何变化。 

3)保存和更新%EBP: 

现在,我们进入了新的函数(callee),需要一个局部栈帧, 使用%EBP指向新的栈帧, 老的%EBP值(属于caller的栈帧)保存在堆栈上, %EBP指向新的栈顶。     push ebp
mov ebp, esp    // ebp <- esp       
然后可以通过%EBP访问函数参数,如8(%ebp),12(%ebp). 注意0(%ebp)是caller的%EBP值,4(%ebp)是函数返回值.  

4)分配局部变量: 

函数可以使用堆栈空间来存放局部变量,直接减去%ESP值就相当于分配了堆栈空间. 分配是按照4Bytes对齐. 此时,局部变量在%ebp和%esp之间. 虽然通过%ebp和%esp都可以访问局部变量,但是约定(convension)使用%ebp寄存器来访问,所以 -4(%ebp)代表第一个局部变量.       

5)保存要使用的寄存器: 

如果这个函数要使用一些寄存器, 需要先保存这些寄存器的值,这些值将被保存在堆栈上,compiler需要记录下保存的顺序,以便之后恢复.       

6)执行函数的功能: 

此时,栈帧已经设置好,所有的参数和局部变量都通过%ebp的偏移来访问.       
16(%ebp) :第三个参数       
12(%ebp) :第二个参数        
8(%ebp) :第一个参数        
4(%ebp) :函数返回值        
0(%ebp) :老的%EBP(caller的%EBP)       
-4(%ebp) :第一个局部变量       
-8(%ebp) :第二个局部变量       
-12(%ebp):第三个局部变量       
函数中可以自由使用任何已经保存过的寄存器, 但是堆栈指针(%esp)不能改变.     

7)释放局部空间:

第四步中函数通过减去%esp来分配局部的临时空间,这里是一个相反的过程,通常通过给%esp加上减去的值来实现,一系列POP指令也能达到相同的效果. 

8)恢复保存的寄存器: 

第五部中保存的寄存器值,在这里按照相反顺序恢复.       

9)恢复老的%ebp: 

恢复第三步中保存的%ebp, 当前的栈帧也就被丢弃掉.       

10)函数返回:

这是callee的最后一步, RET指令从堆栈中弹出%EIP并跳转到那里.控制权重新交回给caller. Ret指令只修改%esp和%eip.       

11)清理压入的参数: 

在__cdecl约定中,caller负责清理堆栈上的参数,和第七步中类似,可以通过POP指令,也可以通过直接加%esp附:X86采用eax作为返回值。 

4.X86主要是采用堆栈传递参数,除非指定以寄存器传递(通过"regparm (NUMBER)"注:NUMBER<=3指定)。

5.如果指定寄存器传递参数,则eax为第一个参数,edx为第二个参数, ecx为第三个参数。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值