hac*_*cks 12 c compiler-construction abi function-call stack-frame
我读到当程序进行函数调用时,被调用函数必须知道如何返回其调用者.
我的问题是:被调用函数如何知道如何返回其调用者?是否有通过编译器在幕后工作的机制?
Car*_*rum 12
编译器遵循特定的"调用约定",定义为您要定位的ABI的一部分.该调用约定将包括一种系统知道返回什么地址的方法.调用约定通常利用硬件对过程调用的支持.例如,在Intel上,返回地址被推送到堆栈:
...处理器在堆栈上按下
EIP寄存器的值(包含指令后面的CALL指令的偏移量)(以后用作返回指令指针).
从函数返回是通过以下ret指令完成的:
...处理器将返回指令指针(偏移)从堆栈顶部弹出到
EIP寄存器中,并在新指令指针处开始执行程序.
相比之下,在ARM上,返回地址放在链接寄存器中:
在
BL和BLX指令复制下一条指令到的地址lr(r14中,链接寄存器).
返回通常通过执行movs pc, lr将链接寄存器中的地址复制回程序计数器寄存器来完成.
参考文献:
编译器知道如何调用函数以及使用哪个调用约定.例如,在C中,函数的参数被推送到堆栈上.调用者可以清除堆栈,因此被调用的函数不必删除参数.其他调用约定可以包括在堆栈上推送参数,并且被调用的函数必须清除它.在这种情况下,生成的代码是这样的,该函数在它返回之前纠正堆栈.调用约定可以在寄存器中传递参数,因此在这种情况下,被调用的函数也不必小心.
CPU具有调用子例程的机制.这将把当前执行地址存储在堆栈上,然后将处理转移到新地址.当函数完成时,它执行一个return语句,它将获取调用者地址并在那里继续执行.
如果返回地址被销毁,因为堆栈没有被正确清理,或者内存被覆盖,那么你会得到未定义的行为.当然,具体的实现细节取决于所使用的平台.
| 归档时间: |
|
| 查看次数: |
1391 次 |
| 最近记录: |