You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM调用约定是否允许函数不将LR寄存器存入栈中?

ARM调用约定中LR寄存器的优化处理:叶函数 vs 非叶函数

这是个非常好的问题,核心在于ARM调用约定里对**叶函数(Leaf Function)**的优化处理——你观察到的现象完全符合标准,编译器确实会根据函数是否调用其他子例程来决定是否将LR寄存器入栈。

1. 什么是叶函数?

像你代码里的function_1这种完全不调用其他子例程的函数,就属于叶函数。这类函数的关键特征是:函数执行过程中不会触发BL(分支并链接)指令——而BL正是会覆盖LR寄存器值的指令(调用子例程时,BL会把当前下一条指令的地址写入LR,作为子例程的返回地址)。

2. 叶函数的LR寄存器处理

对于叶函数来说,从进入函数到执行结束,LR寄存器里始终保存着正确的返回地址(没有任何操作会覆盖它)。所以编译器会做优化:不需要将LR压入栈。这类函数结束时直接执行BX LR就能返回调用者,省去了栈操作的开销,提升了运行效率。

这种优化完全符合ARM调用约定(比如AAPCS)的规范——文档没有强制要求所有函数都保存LR,只要求那些会破坏LR值的函数必须保存它,而叶函数显然不在此列。

3. 非叶函数的LR处理(以你的function_2为例)

function_2调用了function_1,属于非叶函数。当执行BL function_1时,LR寄存器会被覆盖为function_2中BL指令的下一条指令地址——这就把function_2原本的返回地址冲掉了。

所以function_2必须在调用function_1之前,把自己的LR值保存起来(通常是压入栈,编译器也可能根据寄存器使用情况,选择用空闲的非易失性寄存器暂存)。等function_1执行完返回后,function_2再从栈中恢复LR的值,最后通过BX LR返回自己的调用者。

4. 关于文档的补充说明

调用约定文档的核心是定义寄存器的易失性/非易失性规则:

  • 易失性寄存器(比如R0-R3):被调用者可以随意修改,调用者如果需要保留值,必须自己保存;
  • 非易失性寄存器(比如R4-R11):被调用者如果要使用,必须先保存,退出前恢复。

LR的保存要求是隐含在“是否会被修改”的逻辑里的:非叶函数会因为调用其他子例程修改LR,所以必须保存;叶函数不会修改LR,自然不需要额外保存。

内容的提问来源于stack exchange,提问作者Torgon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 08:07:29