NASM汇编实现欧拉计划第1题循环异常求助
欧拉计划第1题NASM汇编循环问题排查与修复
问题背景
刚入门NASM汇编,尝试实现欧拉计划第1题(求1000以内3或5的所有倍数之和)的变体算法——利用倍数的重复间隔模式(+3、+2、+1、+3、+1、+2、+3循环)计算,但汇编代码循环仅执行一次就退出,结果为3;对应的C语言实现可得到正确结果。
正确的C语言实现
int sum = 0, s = 0; int steps[7] = {3,2,1,3,1,2,3}; for (int n = steps[s]; n < 1000; n += steps[s]) { sum += n; s++; if (s == 7) s = 0; }
存在问题的NASM汇编代码
section .data msg db "%d", 10, 0 ;return string for printf (just the result) steps dd 3, 2, 1, 3, 1, 2, 3 ;how the multiples of 3 and 5 are spaced section .text extern printf global main main: xor rax, rax ;prepare rax which will store the result xor rbx, rbx ;prepare rbx, which will be the current number arr0: xor rcx, rcx ;prepare rcx, which will be the array index countup: add rbx, [steps + rcx * 4] ;add steps@rcx to rbx add rax, rbx ;add rbx to the result inc rcx ;increase the array index cmp rcx, 7 ;check if we reached the end of the array je arr0 ;if yes, jump to arr0 cmp rbx, 1000 ;check if we reached 1000 jl countup ;if not, loop again ... print and exit come next
问题分析
原汇编代码存在两处核心逻辑错误:
- 累加与判断顺序颠倒:C代码是先判断当前数是否小于1000,再累加到总和;而原汇编代码先累加,再判断是否继续循环,这会导致可能累加超过1000的数,同时在指令误写等情况下提前退出循环。
- 索引重置后的流程错误:当索引
rcx到达7时跳回arr0清零,但此时没有先判断下一次累加后的数值是否超过1000,直接进入累加逻辑,破坏了循环的判断前置原则。
修改后的正确NASM汇编代码
section .data msg db "%d", 10, 0 ; 格式化输出字符串 steps dd 3, 2, 1, 3, 1, 2, 3 ; 倍数间隔数组 section .text extern printf global main main: xor rax, rax ; rax存储总和,初始化为0 xor rbx, rbx ; rbx存储当前数值,初始化为0 xor rcx, rcx ; rcx作为数组索引,初始化为0 loop_start: ; 计算下一个待判断的数值 add rbx, [steps + rcx * 4] ; 判断当前数值是否超过1000,是则退出循环 cmp rbx, 1000 jge print_result ; 将符合条件的数值累加到总和 add rax, rbx ; 更新数组索引 inc rcx ; 索引到达数组末尾时重置为0 cmp rcx, 7 je reset_index ; 继续循环 jmp loop_start reset_index: xor rcx, rcx jmp loop_start print_result: ; 调用printf输出结果 mov rdi, msg mov rsi, rax xor rax, rax ; 无浮点数参数,清零rax call printf ; 正常退出程序 xor rax, rax ret
修改说明
- 调整了判断与累加的顺序:先计算当前数值,判断是否小于1000,符合条件再累加到总和,完全对齐C代码的逻辑。
- 重构了索引重置流程:将索引重置从循环体中分离,避免重置后直接进入累加,保证每次循环都先执行数值判断。
- 完善了退出与打印流程:明确了循环退出后的打印逻辑,符合x86_64 SysV ABI的函数调用规范。
内容的提问来源于stack exchange,提问作者mattg
相关产品推荐
相关产品推荐

