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

NASM汇编浮点异常:数组模3余1求和逻辑循环失效排查

NASM汇编循环逻辑问题排查与修复

问题描述

需求:编写NASM汇编程序,检查数组中每个元素除以3的余数是否为1,若是则将该元素加入最终总和。

原代码:

SYS_WRITE equ 4
SYS_EXIT equ 1
STDOUT equ 1

segment .data
x: db 3
   db 2
   db 1
   db 3
   db 5
y db 3

segment .bss
res resb 1

segment .text
    global _start

_start:
mov ecx,5 ; number of iterations
xor ebx,ebx ; ebx the sum
mov edx,x ; addres of the first element 
xor eax,eax ;in eax will be the number of elements that are satisfying the conditions i wrote in the text             ;above   

petlja:
push ecx
push edx
push eax
push ebx
mov cl,[y] ; storing 3 in lower 8 bits of cx register
mov ax, [edx]; storing element of array in ax
div cl
cmp ah,1
jnz izlaz
pop ebx
pop eax
pop edx
add ebx,[edx] ;adding to the final sum and increasing the number of elements
inc eax
push edx
push eax
push ebx
izlaz:
pop ebx
pop eax
pop edx
pop ecx
inc edx ; increasing the address
loop petlja

add ebx,'0'; adding character '0' for printing
mov [res],ebx; moving final sum to mem. loc. res
mov eax,SYS_WRITE ; system call for write
mov ebx,STDOUT
mov ecx, res
mov edx, 1
int 80h ; kernel call

mov eax, SYS_EXIT
int 80h ; kernel call

用户问题:单独编写除法取余并判断的逻辑时运行正常,但将其嵌入循环后程序完全无法正常工作,尝试论坛中的多种解决方案均无效,请求排查并解决该循环逻辑问题。


问题排查

  1. 栈平衡被破坏:循环开头push了ecx、edx、eax、ebx四个寄存器,但条件满足时的pop/push操作导致栈内元素数量不匹配,后续循环的寄存器值完全混乱,这是程序崩溃的核心原因。
  2. 除法指令使用错误:div cl是8位除法,要求被除数为AX且高8位AH必须为0,但原代码直接用mov ax, [edx]读取2字节数据(数组元素是1字节db),既读取了错误的数值,又可能因AH不为0触发除法错误。
  3. 数组元素读取错误:数组元素是1字节类型,用ax读取会获取相邻两个字节的数值,导致后续计算完全错误。

修正后的代码

SYS_WRITE equ 4
SYS_EXIT equ 1
STDOUT equ 1

segment .data
x: db 3
   db 2
   db 1
   db 3
   db 5
divisor db 3
newline db 0xA  ; 可选换行符

segment .bss
res_buffer resb 2  ; 预留2字节处理两位数总和

segment .text
    global _start

_start:
    mov ecx, 5          ; 循环次数(数组元素个数)
    xor ebx, ebx        ; ebx存储总和,初始化为0
    mov edx, x          ; edx指向数组第一个元素
    xor eax, eax        ; eax统计符合条件的元素个数

petlja:
    ; 保存循环依赖的寄存器
    push ecx
    push edx

    ; 读取1字节数组元素到al,清零ah避免除法错误
    mov al, [edx]
    xor ah, ah
    mov cl, [divisor]   ; 除数存入cl
    div cl              ; 8位除法,余数存于ah
    cmp ah, 1           ; 判断余数是否为1
    jnz skip_add        ; 不符合则跳过累加

    ; 符合条件,累加元素值并计数
    add ebx, [edx]
    inc eax

skip_add:
    ; 恢复寄存器
    pop edx
    pop ecx

    inc edx             ; 指针移向下一个元素
    loop petlja         ; 自动递减ecx,直到为0终止循环

    ; 将总和转换为ASCII字符串(支持0-99)
    mov ecx, res_buffer
    mov eax, ebx
    xor edx, edx
    mov ebx, 10
    div ebx             ; eax=商(十位),edx=余数(个位)
    add dl, '0'
    mov [ecx+1], dl
    add al, '0'
    mov [ecx], al

    ; 确定输出长度:个位数只输出个位,两位数输出两位
    cmp eax, '0'
    je print_single
    mov edx, 2
    jmp print_start
print_single:
    mov edx, 1
    inc ecx             ; 指针指向个位字符

print_start:
    ; 输出结果
    mov eax, SYS_WRITE
    mov ebx, STDOUT
    int 0x80

    ; 可选:输出换行
    mov eax, SYS_WRITE
    mov ebx, STDOUT
    mov ecx, newline
    mov edx, 1
    int 0x80

    ; 退出程序
    mov eax, SYS_EXIT
    int 0x80

修改说明

  1. 修复栈平衡:仅保存循环中被修改的ecx和edx,跳转后直接恢复,彻底避免栈溢出或寄存器值混乱的问题。
  2. 正确处理除法:用al读取1字节数组元素,提前清零ah确保8位除法的正确性,余数判断逻辑正常工作。
  3. 优化输出逻辑:新增两位数转换逻辑,解决原代码只能输出个位数的限制,适配更大的总和数值。
  4. 简化代码结构:移除冗余的寄存器保存操作,循环逻辑更清晰,降低出错概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:25:32