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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:34:53