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

NASM两数乘除程序调用双过程后执行停滞问题求助

嘿,我之前写NASM程序时也碰到过类似的多过程调用卡住的问题,咱们一步步来拆解排查:

大概率的问题方向及解决办法

1. 寄存器上下文没保存/恢复

NASM里的过程调用如果修改了通用寄存器(比如AX、BX、DX这些),但没在过程开头把它们压栈保存、结尾弹栈恢复的话,会破坏后续过程依赖的寄存器状态,导致程序流程异常。

举个乘法过程的正确示例:

mult_proc:
    push bx          ; 先把会用到的寄存器压栈保存
    push dx
    ; 你的乘法逻辑:比如 mov ax, [num1]; mul word [num2]
    pop dx           ; 用完后按逆序弹栈恢复
    pop bx
    ret

除法过程也要做同样的寄存器保护操作,避免互相干扰。

2. 栈平衡被破坏

如果你的过程用到了栈帧(比如用EBP作为基址指针),但没正确初始化和恢复栈帧,会导致ret指令找不到正确的返回地址,程序直接卡在调用点。

标准的栈帧处理模板:

div_proc:
    push ebp         ; 保存旧的基址指针
    mov ebp, esp     ; 设置当前栈帧基址
    ; 你的除法逻辑
    mov esp, ebp     ; 恢复栈指针
    pop ebp          ; 恢复旧基址指针
    ret

另外,如果用栈传递参数,调用后要记得清理栈(比如add esp, 4),不然栈会越来越乱。

3. 除法过程的DX寄存器没清零

NASM的16位除法(div指令)要求被除数是DX:AX组合(32位),如果你的被除数是16位的,必须先把DX清零,否则DX里的残留值会让被除数变成一个错误的大数值,甚至触发除法错误(比如除数为0、结果溢出),导致程序卡住。

除法过程里必须加这一行:

div_proc:
    ; ... 寄存器保存操作 ...
    mov ax, [num1]   ; 加载被除数到AX
    xor dx, dx       ; 关键!清零DX,确保被除数是AX(16位无符号)
    div word [num2]  ; 商存在AX,余数存在DX
    ; ... 输出逻辑 ...

4. 输入输出缓冲区残留问题

乘法过程执行完后,输入时留下的回车换行符可能还在输入缓冲区里,导致除法过程读取输入时误读这些无效字符,卡在等待输入的状态。

解决办法是在每次读取数字后,手动清理缓冲区:

; 读取数字后,跳过缓冲区里的回车换行
clean_buffer:
    mov al, byte [buffer + ecx]
    cmp al, 0dh
    je clean_done
    inc ecx
    jmp clean_buffer
clean_done:
    ; 可以把缓冲区里的无效字符设为0
    mov byte [buffer + ecx], 0
完整的示例框架参考

给你一个能正常运行的乘除分离的NASM程序模板,你可以对照自己的代码找差异:

section .data
    prompt1 db 'Enter first number: ', 0
    prompt2 db 'Enter second number: ', 0
    msg_mult db 'Product: ', 0
    msg_div db 'Quotient: ', 0
    msg_rem db 'Remainder: ', 0
    newline db 0dh, 0ah, 0

section .bss
    num1 resw 1
    num2 resw 1
    buffer resb 10

section .text
    global _start

_start:
    ; 读取第一个数
    mov eax, prompt1
    call print_string
    call read_number
    mov [num1], ax

    ; 读取第二个数
    mov eax, prompt2
    call print_string
    call read_number
    mov [num2], ax

    ; 依次调用乘除过程
    call multiply
    call divide

    ; 退出程序
    mov eax, 1
    xor ebx, ebx
    int 0x80

; 打印字符串过程
print_string:
    push edx ecx ebx eax
    mov ecx, eax
    call string_len
    mov edx, eax
    mov eax, 4
    mov ebx, 1
    int 0x80
    pop eax ebx ecx edx
    ret

; 获取字符串长度过程
string_len:
    push ebx
    mov ebx, eax
    xor eax, eax
_len_loop:
    cmp byte [ebx], 0
    je _len_done
    inc eax
    inc ebx
    jmp _len_loop
_len_done:
    pop ebx
    ret

; 读取数字并转为16位整数过程
read_number:
    push ebx ecx edx
    mov eax, 3
    mov ebx, 0
    mov ecx, buffer
    mov edx, 10
    int 0x80

    xor ax, ax
    mov ecx, 0
_convert_loop:
    mov bl, byte [buffer + ecx]
    cmp bl, 0dh
    je _convert_done
    sub bl, '0'
    imul ax, 10
    add ax, bx
    inc ecx
    jmp _convert_loop
_convert_done:
    pop edx ecx ebx
    ret

; 乘法过程
multiply:
    push ax bx dx
    mov ax, [num1]
    mul word [num2]  ; DX:AX存储乘积
    ; 打印乘积
    mov eax, msg_mult
    call print_string
    mov eax, ax
    call print_num
    mov eax, newline
    call print_string
    pop dx bx ax
    ret

; 除法过程
divide:
    push ax bx dx
    mov ax, [num1]
    xor dx, dx       ; 必须清零DX!
    div word [num2]  ; 商AX,余数DX
    ; 打印商
    mov eax, msg_div
    call print_string
    mov eax, ax
    call print_num
    mov eax, newline
    call print_string
    ; 打印余数
    mov eax, msg_rem
    call print_string
    mov eax, dx
    call print_num
    mov eax, newline
    call print_string
    pop dx bx ax
    ret

; 打印数字过程
print_num:
    push bx cx dx
    xor cx, cx
    mov bx, 10
_num_loop:
    xor dx, dx
    div bx
    push dx
    inc cx
    cmp ax, 0
    jne _num_loop
_print_digits:
    pop dx
    add dl, '0'
    mov eax, 4
    mov ebx, 1
    mov ecx, edx
    mov edx, 1
    int 0x80
    loop _print_digits
    pop dx cx bx
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:10:23