函数调用过程&栈帧&调用约定

本文深入探讨函数调用过程,包括参数传递、栈帧建立、调用约定如__fastcall、__stdcall和__cdecl的工作原理。讲解了函数返回时的堆栈平衡策略,并解释了为何可变参数必须使用__cdecl约定。同时通过实例展示了不同调用约定的汇编实现。
摘要由CSDN通过智能技术生成

函数调用过程 Procedure

参数传递

考虑函数调用:func(1, 2)
需要把1和2这两个参数进行传递,这里的参数传递可以通过两种方式:
1.参数入栈(内存)
2.参数传递到寄存器
大多数情况下,也是C\C++的默认形式是通过栈进行传递,因为虽然寄存器传递方式快但是寄存器数量有限
参数压入栈中(内存),CS:IP指向下一条指令地址需要进行跳转到函数入口就需要进行原地址的保存,这也是通过压入栈中来解决
注意这里,由于传递哪些参数调用者是知道的,所以参数压入必须由调用者来进行。
通过call指令来跳转同时把原地址压栈保存
跳转后,进入到函数的入口地址,必须做的两件事情:

  1. 将BP寄存器(栈底地址也叫栈基址)设定为SP地址,因为SP始终指向栈顶位置当进行函数调用时,需要建立一个新的栈帧(Stack Frame)这时将基址设定为栈顶即可,但是同时原始的栈基址必须入栈进行保存,所以将先进行push压入BP内容,这是通过sub指令进行
  2. 预留栈空间给局部变量,也就是将SP内容进行设定,设定的值由编译器根据局部变量,临时变量数量自动计算

这两件事情做完后,进行函数体的执行,然后进入到函数返回阶段
函数的返回需要进行2件事情:

  1. 将SP恢复为BP内容,因为在函数进入之初,SP给了BP,然后进行预留空间导致SP在函数退出阶段,和BP中间差了预留空间的长度。所以为了进行“平衡”必须恢复到函数进入之初
  2. 恢复BP内容为上一个栈帧基址,由于在进入之初push了BP所以只需要pop即可

最后进行ret,弹出返回地址并置cs:ip

这时已经返回到调用者的位置,由于之前参数进行了压栈,所以需要把参数都弹出,也就是把SP加上参数占用的空间即可

栈帧 Stack Frame

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值