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
关键修改说明
- 递归调用保护:添加
in_handler标志位,进入中断处理时先检查标志,若已处于处理状态则直接调用原handler,避免嵌套调用导致栈溢出。 - 寄存器完整保存:在自定义逻辑执行前后,保存/恢复所有非DOS规范允许修改的寄存器(BX、CX、DX、SI、DI、BP),确保不会破坏调用者的寄存器状态。
- 按需处理功能:仅对目标功能(如切换目录的3Bh)执行自定义逻辑,其他功能直接跳过,减少不必要的栈操作和递归风险。
- 分离递归处理路径:针对递归调用单独处理,避免栈结构被破坏。
额外注意事项
- DOS的int 21h部分功能(如文件操作、内存分配)是不可重入的,即使添加递归标志,也要避免在自定义逻辑中调用这些不可重入功能,否则依然可能导致系统崩溃。
- 驻留程序的栈空间有限,若自定义逻辑复杂,建议为驻留程序分配独立的栈空间(通过修改SS:SP实现),避免与其他程序的栈冲突。
内容的提问来源于stack exchange,提问作者Benjamin Penney
相关产品推荐
相关产品推荐

