ARM 32位汇编实现1到n打印异常求助:仅输出1
问题排查与修正
错误原因
代码仅打印1次的核心问题是ARM函数调用约定的寄存器使用规则:printf属于外部函数,按照ARM的AAPCS调用约定,r0-r3是临时寄存器,外部函数可以随意修改这些寄存器的值。你把输入的n存在r2中,第一次调用printf后,r2的值已被覆盖,后续循环的cmp r3,r2实际是拿r3和一个被破坏的无效值比较,导致循环直接终止。
另外还有一个小问题:原循环用blt(小于则跳转),当r3等于输入的n时,条件不满足,会跳过打印n本身(比如输入5只会打印1-4)。
修正后的代码
.text .global main main: @ 保存被调用者保存寄存器r4和链接寄存器lr到栈 push {r4, lr} adr r0,format ldr r1,=number bl scanf @ 将输入的n存入r4(被调用者保存寄存器,printf不会修改它) ldr r4,=number ldr r4,[r4] mov r3,#1 loop: mov r1,r3 adr r0,format1 bl printf add r3,r3,#1 cmp r3,r4 ble loop @ 改成小于等于,确保打印到n本身 @ 正常退出,返回值0 mov r0,#0 pop {r4, pc} @ 恢复寄存器并返回 format: .asciz "%d" format1: .asciz "%d\n" @ 标准换行符写法 .data number: .word 0
关键修正点
- 寄存器选择:把
n的值移到r4中,r4属于被调用者保存寄存器,外部函数调用后其值会被保留。 - 栈帧处理:开头
push {r4, lr}保存寄存器,结尾pop {r4, pc}恢复并返回,替代原代码的bl exit,更符合ARM程序的规范写法。 - 循环条件:将
blt改为ble,确保循环执行到r3等于n时仍会打印,覆盖1到n的所有数字。 - 换行符修正:把
format1中的换行改为标准的\n,避免字符串解析问题。 - 退出码修正:将原
mov r0,#1改为mov r0,#0,0是程序正常退出的标准返回码。
编译执行
仍使用你原来的命令:
arm-linux-gnueabi-gcc print_first_n.S -o print_first_n qemu-arm -L /usr/arm-linux-gnueabi ./print_first_n
输入5后,会正常打印1到5的所有数字。
内容的提问来源于stack exchange,提问作者ggz
相关产品推荐
相关产品推荐

