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

MASM打印质数问题:移除USES伪指令后出现无限循环求助

汇编质数检测过程移除USES伪指令后无限循环问题解决

问题背景

需求是按顺序打印x个质数,编写了isPrime过程判断质数,但要求不能使用USES伪指令。移除USES后程序出现无限循环,寻求解决方案。

原带USES伪指令的isPrime过程

isPrime PROC USES ECX EBX
; 检测一个数是否为质数,是则返回布尔值1,否则返回0
; 输入:EAX中存放待检测的数
; 输出:EAX中返回布尔值(0或1)
; 前置条件:EAX的值在[1..200]范围内
; 修改的寄存器:EAX, EBX, ECX, EDX
;-------------------------------------------------------------------------
        mov ecx,eax                         ; 将待检测数p复制到ECX
        mov esi, 2                          ; 初始化循环变量i=2
  startLoop:
        cmp esi,ecx                          
        jge PrimeNum                        ; 若i>=p,说明是质数,跳转到PrimeNum
        mov edx,0
        mov eax,ecx
        div esi                             ; 计算p/i,EAX=p/i,EDX=p%i
        cmp edx, 0                          
        je  NotPrime                        ; 若余数为0,说明不是质数
        inc esi                             ; 否则i自增,继续检测
        jmp startLoop
PrimeNum:   
    mov eax, TRUE                           ; 是质数,返回1
    ret
NotPrime:
    mov eax, FALSE                          ; 不是质数,返回0
    ret
isPrime ENDP

移除USES伪指令后的代码(存在问题)

mov ecx,eax                         ; 将待检测数p复制到ECX
        mov try2, 2                         ; 初始化循环变量i=2
  startLoop:
        cmp try2,ecx                            
        jge PrimeNum                        ; 若i>=p,说明是质数,跳转到PrimeNum
        mov edx,0
        mov eax,ecx
        div try2                                ; 计算p/i,EAX=p/i,EDX=p%i
        cmp edx, 0                          
        je  NotPrime                        ; 若余数为0,说明不是质数
        inc try2                                ; 否则i自增,继续检测
        jmp startLoop
PrimeNum:   
    mov eax, TRUE                           ; 是质数,返回1
    ret
NotPrime:
    mov eax, FALSE                          ; 不是质数,返回0
    ret

问题原因

  1. 寄存器上下文未保存:USES伪指令的作用是自动在过程开头push指定寄存器、结尾pop恢复其状态。原代码中USES ECX EBX会自动保存ECX和EBX,移除后未手动保存被过程修改的ECX,导致调用者(比如主程序)的ECX值被覆盖。若主程序用ECX控制质数打印数量,会直接破坏循环逻辑,引发无限循环。
  2. 过程定义缺失:移除USES后的代码丢失了isPrime PROC和isPrime ENDP的过程边界定义,导致ret指令无法正确找到返回地址,可能引发执行流程混乱。
  3. 全局变量依赖:改用全局变量try2存储循环变量,虽然本身不会直接导致无限循环,但全局变量容易引发上下文污染,不是汇编的最佳实践。

修复后的代码

方案1:保留全局变量,手动保存寄存器

isPrime PROC
; 检测一个数是否为质数,是则返回1,否则返回0
; 输入:EAX中存放待检测的数
; 输出:EAX中返回布尔值(0或1)
; 前置条件:EAX的值在[1..200]范围内
; 修改的寄存器:EAX, ECX, EDX
        push ecx                          ; 手动保存调用者的ECX寄存器

        mov ecx, eax                      ; 将待检测数p存入ECX
        mov try2, 2                       ; 初始化循环变量i=2
startLoop:
        cmp try2, ecx
        jge PrimeNum                      ; 若i>=p,判定为质数
        mov edx, 0
        mov eax, ecx
        div try2                          ; 计算p/i,取余数EDX
        cmp edx, 0
        je NotPrime                       ; 余数为0则不是质数
        inc try2                          ; i自增,继续循环
        jmp startLoop
PrimeNum:
        mov eax, TRUE                     ; 返回1(质数)
        pop ecx                           ; 恢复调用者的ECX寄存器
        ret
NotPrime:
        mov eax, FALSE                    ; 返回0(非质数)
        pop ecx                           ; 恢复调用者的ECX寄存器
        ret
isPrime ENDP

方案2:改用寄存器存储循环变量(推荐)

避免全局变量,改用ESI寄存器存储循环变量,同时手动保存所有被修改的寄存器:

isPrime PROC
; 检测一个数是否为质数,是则返回1,否则返回0
; 输入:EAX中存放待检测的数
; 输出:EAX中返回布尔值(0或1)
; 前置条件:EAX的值在[1..200]范围内
; 修改的寄存器:EAX, ECX, EDX, ESI
        push ecx                          ; 保存调用者的ECX
        push esi                          ; 保存调用者的ESI

        mov ecx, eax                      ; 待检测数p存入ECX
        mov esi, 2                        ; 初始化循环变量i=2
startLoop:
        cmp esi, ecx
        jge PrimeNum                      ; i>=p则为质数
        mov edx, 0
        mov eax, ecx
        div esi                           ; 计算p/i,取余数EDX
        cmp edx, 0
        je NotPrime                       ; 余数为0则非质数
        inc esi                           ; i自增
        jmp startLoop
PrimeNum:
        mov eax, TRUE                     ; 返回1
        pop esi                           ; 恢复ESI
        pop ecx                           ; 恢复ECX
        ret
NotPrime:
        mov eax, FALSE                    ; 返回0
        pop esi                           ; 恢复ESI
        pop ecx                           ; 恢复ECX
        ret
isPrime ENDP

关键说明

  • 手动保存寄存器时,要确保push和pop的顺序相反(先进后出),保证寄存器状态正确恢复。
  • 过程必须保留PROC和ENDP定义,明确过程的起始和结束边界,确保ret指令能正确返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:17:06