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
相关产品推荐
相关产品推荐

