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

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

问题分析

原汇编代码存在两处核心逻辑错误:

  1. 累加与判断顺序颠倒:C代码是先判断当前数是否小于1000,再累加到总和;而原汇编代码先累加,再判断是否继续循环,这会导致可能累加超过1000的数,同时在指令误写等情况下提前退出循环。
  2. 索引重置后的流程错误:当索引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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:55:55