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

ARM树莓派汇编代码无限循环问题求解及原理疑惑

ARM Raspberry Pi汇编无限循环问题解析

我在ARM架构的Raspberry Pi上编写汇编代码,需求是遍历1到用户输入的数值,最终输出首个大于该输入值的数(比如输入5就输出6),这是个基础学习项目。但代码出现了无限循环问题——最初只在check_loop_range标签里加载变量值无法解决,后来在loop_range标签里也加载变量值后问题才解决,我搞不懂其中原理。


初始出错代码

check_loop_range:                       @ Checks if we should continue with loop_range
        ldr r0, =number                 @ r0 <- &number
        ldr r0, [r0]                    @ r0 <- *r0
        ldr r1, =current_number         @ r1 <- &current_number
        ldr r1, [r1]                    @ r1 <- *r1

        cmp r0, r1                      @ compare r0 and r1
        blt end                         @ if r0 <= r1 branch to end

loop_range:                             @ This loop goes trough all numbers from 1 to 'number'
        add r2, r1, #1                  @ Add one to r1
        ldr r1, =current_number         @ r1 <- &current_number
        str r2, [r1]                    @ *r1 <- r2
        b   check_loop_range            @ Continue loop

修正后代码

check_loop_range:                       @ Checks if we should continue with loop_range
        ldr r0, =number                 @ r0 <- &number
        ldr r0, [r0]                    @ r0 <- *r0
        ldr r1, =current_number         @ r1 <- &current_number
        ldr r1, [r1]                    @ r1 <- *r1

        cmp r0, r1                      @ compare r0 and r1
        blt end                         @ if r0 <= r1 branch to end

loop_range:                             @ This loop goes trough all numbers from 1 to 'number'
        ldr r0, =number                 @ r0 <- &number
        ldr r0, [r0]                    @ r0 <- *r0
        ldr r1, =number                 @ 此处为笔误,应为current_number
        ldr r1, [r1]                    @ r1 <- *r1

        add r2, r1, #1                  @ Add one to r1
        ldr r1, =current_number         @ r1 <- &current_number
        str r2, [r1]                    @ *r1 <- r2
        b   check_loop_range            @ Continue loop

完整工作代码

/* The data section hold the variables we will use */
.data

.align 4
number:                 .word 0         @ Input give by the user

.align 4
scan_pattern:           .asciz "%d"     @ Pattern to pass as argument to scanf

.align 4
print_pattern:          .asciz "%d\n"   @ Pattern to pass as argument to printf

.align 4
number_abundant:        .word 0         @ The number of abundant numbers from 1 to 'number'

.align 4
number_deficient:       .word 0         @ The number of deficient numbers from 1 to 'number'

.align 4
number_perfect:         .word 0         @ The number of perfect numbers from 1 to 'number'

.align 4
current_number:         .word 1         @ We start evaluating numbers from 1, up to 'number'

.align 4
return:                 .word 0         @ We will store lr here on function calls

/* Code Section */

.text

.global main
main:
        ldr r1, =return                 @ r1 <- &return
        str lr, [r1]                    @ *r1 <- lr             ; save return address

        ldr r0, =scan_pattern           @ r0 <- &scan_pattern   ; first argument to scanf
        ldr r1, =number                 @ r1 <- &number         ; second argument to scanf
        bl  scanf                       @ call scanf

check_loop_range:                       @ Checks if we should continue with loop_range
        ldr r0, =number                 @ r0 <- &number
        ldr r0, [r0]                    @ r0 <- *r0
        ldr r1, =current_number         @ r1 <- &current_number
        ldr r1, [r1]                    @ r1 <- *r1

        cmp r0, r1                      @ compare r0 and r1
        blt end                         @ if r0 <= r1 branch to end

loop_range:                             @ This loop goes trough all numbers from 1 to 'number'
        ldr r0, =number                 @ r0 <- &number
        ldr r0, [r0]                    @ r0 <- *r0
        ldr r1, =number                 @ 此处为笔误,应为current_number
        ldr r1, [r1]                    @ r1 <- *r1

        add r2, r1, #1                  @ Add one to r1
        ldr r1, =current_number         @ r1 <- &current_number
        str r2, [r1]                    @ *r1 <- r2
        b   check_loop_range            @ Continue loop

end:
        ldr r0, =print_pattern
        ldr r1, =current_number
        ldr r1, [r1]
        bl  printf

        ldr lr, =return                 @ lr <- &return
        ldr lr, [lr]                    @ lr <- *lr
        bx  lr                          @ exit

/* External */
.global printf
.global scanf

Makefile

all: Pro04

Pro04: Pro04.o
        gcc -o $@ $+

Pro04.o: Pro04.s
        as -g -mfpu=vfpv2 -o $@ $<

clean:
        rm -vf Pro04 *.o

系统环境信息

Architecture:          armv7l
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             1
Model name:            ARMv7 Processor rev 4 (v7l)
CPU max MHz:           1200.0000
CPU min MHz:           600.0000
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

问题解析

初始代码无限循环的原因

  1. 退出条件的指令与注释不符:
    注释写的是if r0 <= r1 branch to end,但实际用的blt指令是当第一个操作数小于第二个操作数时跳转(即r0 < r1时退出),而非小于等于。这意味着当current_number等于number时(r0 == r1),不会触发跳转,会继续进入循环。

  2. 寄存器用途混淆导致的逻辑异常:
    在loop_range中,你先使用r1存储current_number的数值做加法,随后又将r1赋值为current_number的内存地址用于存值。虽然跳回check_loop_range后会重新加载r1,但如果出现极端情况(比如number的数值刚好等于current_number的内存地址),会导致加法计算出错误值,无法正确更新current_number,最终陷入循环。

修正后代码的解决原理

你在loop_range中重新加载r0和r1的数值(注意此处有笔误,应将ldr r1, =number改为ldr r1, =current_number),本质是强制每次循环都从内存读取最新变量值,彻底避免了寄存器中残留的旧值(比如之前的内存地址)干扰计算逻辑。

另外,你修正后的笔误实际上让current_number直接被设为number+1,跳过了中间遍历步骤,所以看起来快速退出了循环,但这不是正确的遍历逻辑。更合理的修正应该是固定寄存器用途,比如用r1始终存current_number的地址,r2存数值,避免混淆:

check_loop_range:
        ldr r0, =number
        ldr r0, [r0]
        ldr r1, =current_number
        ldr r2, [r1]  ; 用r2存current_number的数值

        cmp r0, r2
        blt end

loop_range:
        add r2, r2, #1  ; 直接对数值做加法
        str r2, [r1]    ; r1始终是地址,无需重新加载
        b check_loop_range

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:52:02