【问题标题】:x86 Assembly (NASM): Floating Point Exception, not dividing by 0?x86 程序集(NASM):浮点异常,不除以 0?
【发布时间】:2026-01-13 09:15:02
【问题描述】:

我正在尝试计算表达式A * B + ( A + B ) / ( A - B ),其中 A 和 B 是用户输入的整数。我在 linux 内核上使用 ALong32 库。

%include "along32.inc"

section .data
msg1    db      'Enter A: ', 0
msg2    db      'Enter B: ', 0
msg3    db      'Result: ' , 0
err     db      'Error: cannot divide by 0', 0
A       resb    4
B       resb    4

section .text

global main

main:
    mov     edx,    msg1
    call    WriteString
    call    ReadInt
    mov     [A],    eax  ; move the input into A

    mov     edx,    msg2
    call    WriteString
    call    ReadInt      ; move the next number into eax

    cmp     eax,    [A]  ; compare A and eax (B)

    je      error        ; if A and B are equal, error

    mov     [B],    eax  ; move eax into B 

    mov     eax,    [A]
    add     eax,    [B]
    mov     ebx,    eax ; ebx = A + B

    mov     eax,    [A]
    sub     eax,    [B] ; eax = A - B

    div     ebx        

    mov     ebx,    eax ; ebx = (A + B) / (A - B)

    mov     ecx,    [B]
    mov     eax,    [A]
    mul     ecx        
    mov     ecx,    eax ; ecx = A * B

    add     eax,    ecx ; eax = A * B + (A + B) / (A - B)

    mov     edx,    msg3
    call    WriteString
    call    WriteInt

    jmp end

error:
    mov     edx,    err
    call    WriteString
    jmp end

end:
    mov     eax,    1
    int     0x80

我觉得我已经评论了我做得很好,但如果需要,我会更深入地解释我正在做的事情。

当我运行这段代码时,输​​入两个数字后,我得到一个floating point exception,程序退出。

为什么会这样?我检查除以 0。

【问题讨论】:

  • 您忘记阅读 DIV 的指令集参考页面并且忘记搜索 *。
  • 我看了这两个!所有其他关于此的 SO 问题都与除以 0 相关,我检查了这些问题。 @小丑
  • 例如参见thisthis
  • 我不明白这些答案以及它们与我的问题的关系!我使用 EAX 作为商,我什至没有编辑 edx。除非我需要在使用前清除它? @小丑
  • 哪一部分令人困惑? DIV 在您使用时将使用 edx 作为股息的前 32 位,而您无需设置它。 TL;DR:您需要在 DIV 之前将 edx 归零。

标签: assembly nasm


【解决方案1】:

我发现你的程序有 2 个问题。

  • div ebx 指令使用 EDX:EAX 作为被除数,而您未能设置它。只需插入xor edx,edx

    xor   edx, edx ; <--------------------------------- Add this !
    div   ebx        
    mov   ebx, eax ; ebx = (A + B) / (A - B)
    
  • 除法后,您将商存储在 EBX 中,但您再也不会拿起它来显示结果!

    mov   ecx, [B]
    mov   eax, [A]
    mul   ecx
    mov   ecx, eax ; ecx = A * B
    mov   eax, ebx ; <--------------------------------- Add this !
    add   eax, ecx ; eax = A * B + (A + B) / (A - B)
    

第二个问题可以用更短的方式解决:

mov   ecx, [B]
mov   eax, [A]
mul   ecx
add   eax, ebx ; eax = A * B + (A + B) / (A - B)

编辑(迟到了,抱歉)

我检查除以 0。

A * B + ( A + B ) / ( A - B )

您的检查基于分隔符(A - B),因此如果A 等于B,则退出。
正确,但程序代码错误地计算了(A - B) / (A + B),因此使用(A + B) 作为分隔符!

这是我的计算版本A * B + ( A + B ) / ( A - B )

mov     ebx, [A]
sub     ebx, [B]    ; EBX = (A - B)
jz      error       ; Guard against division by zero!

mov     eax, [A]
add     eax, [B]    ; EAX = (A + B)

xor     edx, edx    ; EDX:EAX = (A + B)
div     ebx         ; EAX = (A + B) / (A - B)

mov     ebx, [A]
imul    ebx, [B]    ; EBX = A * B

add     eax, ebx    ; EAX = A * B + (A + B) / (A - B)

【讨论】: