ARM7TDMI参数传递问题:栈指针越界报错排查
问题分析与解决
代码重现
.data CHAR_TO_FIND: .byte 'A' STRING_DATA: .asciz "HELLO ARM7" STRING_LENGTH: .word 10 .text ldr r0 ,= STRING_DATA ldr r1 ,= CHAR_TO_FIND ldrb r1 , [r1] mov r2 , #10 stmfa sp! , {r0 , r2} bl char_find swi 0x11 char_find: ldmfa sp! , {r3 , r4}
错误原因
出现“stack pointer moved beyond stack frame”的核心原因是栈操作不匹配,且未处理bl指令自动压入的返回地址:
- 执行
stmfa sp! , {r0 , r2}时,栈中压入2个32位寄存器(共8字节),SP指向栈顶的r2。 - 执行
bl char_find时,ARM硬件会自动将当前返回地址(LR寄存器的值)压入栈,此时栈中共有3个32位元素:[r0][r2][LR],SP指向LR。 - 进入
char_find后,仅用ldmfa sp! , {r3 , r4}弹出2个元素,SP仅回退8字节,栈中残留LR的值。函数返回后,主程序SP未回到压栈前的初始位置,后续栈操作会破坏栈帧结构,触发调试器的栈指针越界检测。
解决方法
方法1:匹配栈操作数量,正确处理返回地址
在char_find中弹出所有压入栈的元素(包括bl自动压入的LR),通过LR返回:
char_find: ldmfa sp! , {r3 , r4, lr} ; 弹出r0→r3,r2→r4,LR→lr ; 此处编写字符查找逻辑 mov pc, lr ; 跳回主程序
操作后SP会回到主程序压栈前的位置,栈帧恢复正常。
方法2:遵循ARM调用约定,使用帧指针管理栈帧
建立函数栈帧,通过帧指针(FP)访问主程序传入的参数,避免直接弹出导致的栈混乱:
char_find: stmfa sp!, {fp, lr} ; 保存旧帧指针和返回地址 mov fp, sp ; 设置新帧指针,绑定当前栈帧 ldr r3, [fp, #8] ; 通过帧指针偏移获取主程序压入的r0 ldr r4, [fp, #12] ; 获取主程序压入的r2 ; 此处编写字符查找逻辑 ldmfa sp!, {fp, pc} ; 恢复帧指针,加载返回地址完成返回
这种方式贴合ARM标准调用规范,栈帧结构清晰,不易出错。
额外建议
ARM7通常使用满递减栈(FD),建议将stmfa/ldmfa替换为stmfd/ldmfd,更贴合通用调用约定,减少栈管理混淆。
内容的提问来源于stack exchange,提问作者Noxpox
相关产品推荐
相关产品推荐

