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

x86汇编实现素数判断程序时遇Integer Overflow错误求助

x86汇编素数判断程序的整数溢出错误排查

我正在编写一个x86汇编程序,用于接收用户输入的无符号32位整数并判断其是否为素数。目前已实现输入数字(InputNumber过程)和输入0退出的逻辑,但isPrime过程存在问题:在执行div eax指令(对应代码第122行)时持续触发"Integer Overflow"错误,该指令原本用于计算n的最大除数(将n除以2)。以下是完整代码:

TITLE Determine Whether Number is Prime, Version 1 (isPrime.asm)

; This program takes 32-bit unsigned 
; integers and sees if they are prime numbers;
; it also displays the time taken to determine
; this information.
; Name: Kasizah
; Date: 11-07-2022

INCLUDE Irvine32.inc

.data
dPrompt BYTE    "Enter a non-negative integer (0 to exit): ",0
n       DWORD   ?

; time data
startTime   DWORD   ?   ; start time
timeTaken   DWORD   ?   ; time taken to perform process

; message strings
notPositive BYTE    "ERROR: 'n' must be positive.",0
numPrime    BYTE    " is a prime number.",0
notPrime    BYTE    " is not a prime number; it is divisible by ",0
endstr      BYTE    ".",0
nEqualsOne  BYTE    "1 is not a prime number.",0
timeTakenSt BYTE    "This computation took ",0
timeTakenEn BYTE    " milliseconds.",0

.code
main PROC
    input:
        call InputNumber            ; checks to see if number is zero
        cmp  n,0                    ; compare value to zero
        jl   LTZError               ; go to process for error message that 
                                    ;       states that number must be positive
        ja   process                ; if positive, jump to process
        jmp  quit                   ; else number is zero
    LTZError:
        mov  edx,OFFSET notPositive ; state that 'n' must be positive
        call WriteString
        call Crlf                   ; jump to next line
        jmp  input                  ; return to input
    process:
        call GetMseconds            ; get start time
        mov  startTime,eax
        cmp  n,1                    ; if 'n' is 1, jump to notPrimeNum
        je   numIsOne               ; jump to numIsOne
        call isPrime                ; else call isPrime to see if number is prime
        ; jump based on whether or not 'n' is prime
        cmp  eax,0
        jz   primeNum               ; EAX is 0, number is prime
        jmp  notPrimeNum            ; else, say that number isn't prime
    
    ; PRIME OR NOT PRIME STATMENTS
    primeNum:
        mov  eax,n                  ; number is prime
        call WriteInt
        mov  edx,OFFSET numPrime    ; state that number is prime
        call WriteString
        call Crlf                   ; jump to next line
        jmp  getTime                ; jump to getTime
    notPrimeNum:
        mov  ebx,eax                ; copy number stored in EAX
        mov  eax,n                  ; write 'n'
        call WriteInt
        mov  edx,OFFSET notPrime    ; load notPrime into EDX
        call WriteString
        mov  eax,ebx                ; move EBX back into EAX
        call WriteInt
        mov  edx,OFFSET endstr      ; move endstr into EDX
        call WriteString
        call Crlf                   ; jump to next line
        jmp  getTime                ; jump to getTime
    numIsOne:
        mov  edx,OFFSET nEqualsOne  ; load nEqualsOne into EDX
        call WriteString
        call Crlf                   ; jump to next line
        jmp  getTime                ; jump to getTime
    
    ; SEE HOW MUCH TIME WAS TAKEN
    getTime:
        call GetMseconds            ; get process end time
        sub  eax,startTime          ; subtract startTime from time received
        mov  ebx,1000               ; multiply EAX by 1000
        mul  ebx
        ; output time taken
        mov  edx,OFFSET timeTakenSt ; load timeTakenSt into EDX
        call WriteString
        call WriteInt               ; output time as integer
        mov  edx,OFFSET timeTakenEn ; load timeTakenEn into EDX
        call WriteString
        call Crlf                   ; jump to next line
        jmp  input                  ; return to input
    quit:
        exit                        ; exit the program
main ENDP
;----------------------------------------------
InputNumber PROC
;
; Prompts the user to input a number. The
;   number is saved for later use.
; Receives: nothing
; Returns: nothing
;----------------------------------------------
    mov  edx,OFFSET dPrompt ; display prompt
    call WriteString
    call ReadInt            ; reads 32-bit integer in from keyboard
    mov  n,eax              ; move EAX into n
    ret
InputNumber ENDP
;----------------------------------------------
isPrime PROC
;
; Takes a 32-bit number and determines if 
;   it is prime.
; Receives: EAX
; Returns: EAX
;----------------------------------------------
    mov  edx,n              ; move 'n' into EDX
    mov  eax,2              ; move 2 into EAX
    div  eax                ; divide EDX by 2
    mov  ecx,eax            ; move EAX into ECX
    check_loop:
        mov  eax,n              ; move 'n' into EAX
        xor  edx,edx            ; reset EDX to 0 so that it doesn't interfere
        div  ecx                ; divide EAX by ECX
        test edx,edx            ; testing EDX against itself will set the zero flag 
                                ;       if EDX is zero
        jz   not_prime          ; EDX is zero, jump to not_prime
        cmp  ecx,1              ; else check to see if ECX is 1
        je   end_loop           ; if 1, end loop
    not_prime:
        mov  eax,ecx            ; store ECX in EAX
        jmp  quit               ; quit process
    end_loop:
        mov  eax,0              ; as loop ran until ECX equaled 1, 'n' must 
                                ;       be prime; set EAX to 0
        jmp quit                ; quit process
    quit:
        ret
isPrime ENDP
END main

错误原因分析

触发整数溢出的核心问题是isPrime过程中对div指令的使用逻辑错误:

  • x86汇编中,无符号除法指令div的被除数默认是EDX:EAX的64位组合值,操作数是除数。你当前的代码把n存入EDX,又把2存入EAX,执行div eax时,相当于用EDX<<32 | EAX这个64位大数除以2,结果会超出EAX的32位存储范围,直接触发整数溢出。
  • 你原本的意图是计算n/2,正确的做法应该是把n放入EAX,清空EDX(无符号除法必须保证EDX为0,避免高位数据干扰),再用div除以2。

修复方案

1. 修正isPrime过程的除法逻辑

修复后的isPrime过程如下,同时补充了循环递减逻辑(原代码缺少dec ecx会导致死循环):

isPrime PROC
;
; Takes a 32-bit number and determines if 
;   it is prime.
; Receives: 全局变量n
; Returns: EAX(0表示素数,非0值为约数)
;----------------------------------------------
    mov  eax,n              ; 将n放入EAX作为被除数
    xor  edx,edx            ; 无符号除法前清空EDX,避免高位干扰
    mov  ebx,2              ; 设置除数为2
    div  ebx                ; n除以2,结果存入EAX,余数存入EDX
    mov  ecx,eax            ; 将最大检查范围存入ECX

    check_loop:
        mov  eax,n              ; 重新加载n到EAX
        xor  edx,edx            ; 清空EDX
        div  ecx                ; n除以当前ECX的值
        test edx,edx            ; 检查余数是否为0
        jz   not_prime          ; 余数为0,说明不是素数
        dec  ecx                ; 除数减1,继续下一次检查
        cmp  ecx,1              ; 检查是否已遍历到1
        je   end_loop           ; 遍历到1则说明是素数
        jmp  check_loop         ; 继续循环

    not_prime:
        mov  eax,ecx            ; 返回找到的约数
        jmp  quit
    end_loop:
        mov  eax,0              ; 返回0表示是素数
    quit:
        ret
isPrime ENDP

2. 修正时间计算逻辑

原getTime部分的mul ebx会把毫秒数乘以1000,导致输出的时间单位与提示文字"milliseconds"不符,直接删除该乘法指令即可:

getTime:
    call GetMseconds            ; 获取结束时间
    sub  eax,startTime          ; 计算时间差(毫秒)
    ; 移除mul ebx指令
    mov  edx,OFFSET timeTakenSt
    call WriteString
    call WriteInt
    mov  edx,OFFSET timeTakenEn
    call WriteString
    call Crlf
    jmp  input

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:45:55