Apple Silicon ARM64架构下BL指令跳转异常问题排查
ARM64递归斐波那契汇编中BL指令异常问题分析
问题代码
.section __TEXT,__text,regular,pure_instructions _main: mov X0, 5 bl fib bl exit fib_end: mov X0, 0 b exit .align 2 fib: stp fp, lr, [sp, -16]! mov fp, sp ; BASE CONDITION cmp X0, 1 b.le fib_base_case mov X4, X0 sub X0, X0, 1 mov lr, 0 bl fib mov lr, x9 mov X3, X0 ; result for fib (n-1) mov X0, X4 sub X0, X0, 2 bl fib add X0, X0, X3 ; adding the results ldp fp, lr, [sp], 16 ret fib_base_case: ldp fp, lr, [sp], 16 ret exit: mov X16, #1 svc 0x80 ret
问题描述
编写递归实现斐波那契数列的ARM64汇编代码时,标记的bl fib指令执行后,链接寄存器(LR)更新正确,但程序计数器(PC)并未回到函数开头;将其替换为普通分支指令后,跳转功能恢复正常,询问该差异的原因。
原因分析
核心问题是手动修改lr寄存器,彻底破坏了BL指令的返回逻辑:
bl指令的本质是跳转+保存返回地址:执行bl fib时,CPU会自动把当前指令的下一条指令地址存入lr,后续通过ret指令(将lr的值加载到PC)就能回到调用点继续执行。- 你在第一次
bl fib前执行了mov lr, 0,直接覆盖了BL本该保存的返回地址;之后又执行mov lr, x9,但x9是未初始化的垃圾值。这导致递归调用完成后执行ret时,PC会跳转到错误的地址,表现为“没回到函数开头”。 - 换成普通
b fib指令时,它只做单纯跳转,不依赖lr实现返回,所以不受修改lr的影响,跳转功能自然正常。
修正建议
直接删除mov lr, 0和mov lr, x9这两行多余代码即可。递归调用的返回地址会由bl自动存入lr,你已经通过stp fp, lr, [sp, -16]!把lr保存到栈上,后续ldp fp, lr, [sp], 16会恢复正确的返回地址,最后ret就能正常回到调用点。
内容的提问来源于stack exchange,提问作者Adar Maori
相关产品推荐
相关产品推荐

