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

MS-DOS中替换int 21h中断向量后程序挂起的问题求助

解决MS-DOS中替换int 21h中断向量后程序挂起的问题

你的程序挂起的核心原因是递归调用导致栈溢出,以及中断处理程序的调用规范问题:

  • 递归调用:DOS的int 21h内部部分功能会再次触发int 21h(比如命令提示符输出、部分文件操作),你的中断处理程序会被反复嵌套调用,每次调用都会在栈上压入FLAGS、返回地址,最终栈空间耗尽导致程序挂起。即使移除print_star,这个问题依然存在——只要嵌套调用次数足够多,栈就会溢出。
  • 中断调用的栈结构风险:虽然你用pushf + call调用原中断向量的方式看似栈结构正确,但DOS的int 21h并非完全可重入,嵌套调用很容易破坏系统状态。

修改后的代码(WASM风格)

.model tiny
.code
    org 100h

start:
    jmp install

; -----------------------------------------------------------------------------
; RESIDENT PART
; -----------------------------------------------------------------------------

old_int21_vector    dd 0
in_handler          db 0  ; 递归调用标志,0=未进入handler,1=正在处理

new_int21_handler:
    ; 检查是否处于递归调用中
    push ax
    mov al, [cs:in_handler]
    or al, al
    jnz call_old_directly  ; 递归调用时直接执行原handler,不做自定义处理
    mov [cs:in_handler], 1 ; 置位递归标志
    pop ax

    ; 保存所有可能被修改的寄存器(遵循DOS中断规范)
    push bx
    push cx
    push dx
    push si
    push di
    push bp

    ; 按需处理特定int 21h功能(这里以切换目录功能3Bh为例)
    cmp ah, 3Bh
    jne skip_custom_logic

    ; 调用原DOS中断处理程序
    pushf
    call dword ptr cs:old_int21_vector

    ; 执行自定义操作(比如打印星号)
    call print_star
    jmp cleanup_handler

skip_custom_logic:
    ; 非目标功能,直接调用原中断
    pushf
    call dword ptr cs:old_int21_vector

cleanup_handler:
    ; 恢复寄存器
    pop bp
    pop di
    pop si
    pop dx
    pop cx
    pop bx

    ; 清除递归标志
    push ax
    mov [cs:in_handler], 0
    pop ax

    iret

; 递归调用时直接跳转执行原handler,避免嵌套栈溢出
call_old_directly:
    pop ax
    pushf
    call dword ptr cs:old_int21_vector
    iret

print_star:
    push ax
    push bx
    mov ah, 0Eh
    mov al, '*'
    mov bx, 0
    int 10h
    pop bx
    pop ax
    ret

resident_end label byte

; -----------------------------------------------------------------------------
; INSTALLATION PART
; -----------------------------------------------------------------------------
install:
    ; 获取原int21h向量
    mov ax, 3521h
    int 21h
    mov word ptr old_int21_vector[0], bx
    mov word ptr old_int21_vector[2], es

    ; 设置新的int21h向量
    mov dx, offset new_int21_handler
    mov ax, 2521h
    int 21h

    ; 驻留程序退出,计算驻留大小(按16字节对齐)
    mov ax, 3100h
    mov dx, offset resident_end
    add dx, 15
    mov cl, 4
    shr dx, cl
    int 21h

end start

关键修改说明

  1. 递归调用保护:添加in_handler标志位,进入中断处理时先检查标志,若已处于处理状态则直接调用原handler,避免嵌套调用导致栈溢出。
  2. 寄存器完整保存:在自定义逻辑执行前后,保存/恢复所有非DOS规范允许修改的寄存器(BX、CX、DX、SI、DI、BP),确保不会破坏调用者的寄存器状态。
  3. 按需处理功能:仅对目标功能(如切换目录的3Bh)执行自定义逻辑,其他功能直接跳过,减少不必要的栈操作和递归风险。
  4. 分离递归处理路径:针对递归调用单独处理,避免栈结构被破坏。

额外注意事项

  • DOS的int 21h部分功能(如文件操作、内存分配)是不可重入的,即使添加递归标志,也要避免在自定义逻辑中调用这些不可重入功能,否则依然可能导致系统崩溃。
  • 驻留程序的栈空间有限,若自定义逻辑复杂,建议为驻留程序分配独立的栈空间(通过修改SS:SP实现),避免与其他程序的栈冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:42:03