ARM汇编英寸转英尺程序输出异常求助:寄存器值正确但输出错误
ARM汇编英寸转英尺输出异常问题排查
输入67英寸时,程序输出5英尺和-307609856英寸,调试阶段寄存器值符合预期,但终端输出结果错误。尝试修改寄存器引用后,r3值仍会被重置为初始值,无法保留计算后的余数。
原代码
.text .global main main: SUB sp, sp, #4 STR lr, [sp] # 提示用户输入 LDR r0, =prompt BL printf # 读取输入值 LDR r0, =formatString LDR r1, =inches BL scanf # 除法运算(求英尺和余数英寸) LDR r0, =inches LDR r0, [r0] MOV r1, #12 MOV r2, #0 MOV r3, r0 # 循环求余数 loop: CMP r3, r1 BLT exit // 余数小于12时退出循环 SUB r3, r3, r1 // 减去12,计算余数 ADD r2, r2, #1 // 统计英尺数 B loop exit: # 输出英尺数 MOV r1, r2 LDR r0, =output1 BL printf # 输出英寸余数 MOV r1, r3 LDR r0, =output2 BL printf LDR lr, [sp] ADD sp, sp, #4 MOV pc, lr .data prompt: .asciz "enter height in inches: " formatString: .asciz "%d" inches: .word 0 output1: .asciz "\nheight in feet is %d\n" output2: .asciz "height in inches is %d\n"e
问题根源
ARM汇编的调用约定中,r0-r3属于临时寄存器(调用者保存寄存器),被调用函数(比如printf)可以随意修改这些寄存器的值。你在exit标签后先调用了一次printf输出英尺数,这次调用会直接覆盖r3的内容,导致后续输出时r3已经不是之前计算的余数,而是printf执行后的垃圾值。
解决方法
在调用第一个printf前,把r3的余数保存到栈或者数据段变量中,等第一个printf执行完再恢复r3的值。
修改后的代码示例(用栈保存r3)
.text .global main main: SUB sp, sp, #8 // 多分配4字节空间保存r3 STR lr, [sp] # 提示用户输入 LDR r0, =prompt BL printf # 读取输入值 LDR r0, =formatString LDR r1, =inches BL scanf # 除法运算(求英尺和余数英寸) LDR r0, =inches LDR r0, [r0] MOV r1, #12 MOV r2, #0 MOV r3, r0 # 循环求余数 loop: CMP r3, r1 BLT exit // 余数小于12时退出循环 SUB r3, r3, r1 // 减去12,计算余数 ADD r2, r2, #1 // 统计英尺数 B loop exit: STR r3, [sp, #4] // 将余数r3保存到栈中(lr下方的位置) # 输出英尺数 MOV r1, r2 LDR r0, =output1 BL printf # 从栈中恢复r3的值 LDR r3, [sp, #4] # 输出英寸余数 MOV r1, r3 LDR r0, =output2 BL printf LDR lr, [sp] ADD sp, sp, #8 // 释放栈空间 MOV pc, lr .data prompt: .asciz "enter height in inches: " formatString: .asciz "%d" inches: .word 0 output1: .asciz "\nheight in feet is %d\n" output2: .asciz "height in inches is %d\n"
其他可选方案
- 把余数保存到数据段的一个变量中,比如在
.data里加remainder: .word 0,计算完后用STR r3, =remainder保存,输出前用LDR r3, =remainder读取。 - 使用r4-r12这类被调用者保存寄存器(需要在函数开头保存,结尾恢复),比如把余数存在r4里,调用
printf前不用额外保存,因为printf会保留r4-r12的值(前提是遵循调用约定)。
内容的提问来源于stack exchange,提问作者freckledface
相关产品推荐
相关产品推荐

