寄存器的使用惯例和调用过程的栈

本文讨论了IA32架构下寄存器的使用惯例,包括调用者保存和被调用者保存的寄存器,并通过具体示例说明了函数调用过程中寄存器及栈的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、寄存器的使用惯例

       IA32为例子,

      %eax,   %edx,   %ecx   -----  调用者保存的寄存器值 (覆盖)

      %ebx,  %esi,   %edi   ------    被调用者保存的寄存器值(先保存 ,压栈,返回前恢复)

  例子:int  p(int x)

             {

                        int y = x * x;

                        int z = Q(y);

                        return y + z;

              }   

p : 调用者    Q:被调用者

那么在这里我就想讨论一下,这里的y在哪里存储:

  方式一:  存在p自己的栈中,当Q返回时,直接就可以找到y的值。(保存在调用者)

  方式二:   存在Q的栈中,如果Q想使用这个寄存器,那么就先吧值存在自己的栈中,然后,当Q的调用结束后,就直接恢复该寄存器的值,y的值就被Q这个函数,给返回来。                (被保存在被调用者)

那么这两个方法计算机会选择那种方式,IA32 都采用,是不是很厉害,他就是将寄存器分为了,调用者保存   --- 被调用者保存。

二、调用过程的栈

void swap(int *x,int *y)
{
	int tmp;
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
int call()
{
	int arg1 = 534;
	int arg2 = 1057;
	swap(&arg1,&arg2);
	return arg1 - arg2;
}

图示过程:



    

### RISC-V 架构下的函数调用约定与帧布局 #### 帧布局概述 在 RISC-V 的 ABI 中,帧的设计是为了支持函数调用过程中的局部变量存储、参数传递以及上下文保存等功能。帧通常由指针(SP)管理,其布局遵循一定的规则以确保跨平台兼容性效率[^5]。 - **的增长方向**:RISC-V 的是从高地址向低地址增长的。 - **帧结构**: - 底通常是当前函数的返回地址(RA 寄存器的内容会被压入中)。 - 随后是上一层函数的帧边界。 - 局部变量临时数据会分配在帧的较低地址区域。 #### 参数传递机制 RISC-V 的函数调用约定明确规定了参数如何传递: - 如果参数数量较少,则优先使用寄存器 `a0` 至 `a7` 来传递参数[^1]。 - 当参数超过 8 个或者某些复杂类型的参数无法完全放入寄存器时,剩余的部分将通过进行传递。 - 对于浮点数类型的数据,如果目标硬件支持 FPU,则可能利用专门的浮点寄存器来进行传输[^3]。 #### 堆清理责任 关于堆清理的责任划分,在不同的调用惯例中有差异: - 在 CDECL 类型的标准下,一般是由调用方负责调整指针回到原始位置之后再继续执行后续操作。 - 而对于一些特定优化场景或是中断服务例程等情况,也可能存在被叫函数自行处理退出前恢复现场的情形。 #### 返回值传递方式 针对简单数值类别的结果反馈,常规做法是指定首个可用的结果接收容器即 `a0` 或者组合形式如双精度实数需占用连续两个槽位(`a0`, `a1`)完成交付动作;而对于较大尺寸的对象拷贝任务,则往往预先安排好一块内存缓冲区作为暂存场所并通过额外指示告知确切方位信息以便取回最终产物[^4]。 ```python # 示例代码展示了一个简单的函数调用流程模拟 def function_call_simulation(): # 初始化寄存器 a0-a7 sp (假设为简化模型) registers = {'sp': 0x7ffffffc, 'ra': None} def caller_function(): nonlocal registers # 准备参数并设置到相应寄存器中 registers['a0'] = 10 registers['a1'] = 20 # 更新指针预留空间用于保存 ra 及其他必要项 registers['sp'] -= 8 # 模拟跳转至 callee 并记录返回地址 registers['ra'] = addresses['callee'] # 执行实际转移逻辑此处省略具体实现细节 def callee_function(): nonlocal registers # 处理传入参数... result_value = perform_computation(registers['a0'], registers['a1']) # 将结果写入默认返回值寄存器 registers['a0'] = result_value # 清理本地使用的资源并将控制权交还给调用者 restore_context() jump_back_to_address(registers['ra']) caller_function() # 启动整个链条运作 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值