别光编译Hello World了!用DosBox+Masm6.15带你复现一个经典的DOS内存驻留程序(TSR)

从键盘热键到内存驻留:用DosBox+Masm6.15复活DOS时代的TSR黑科技

还记得DOS时代那些神奇的内存驻留程序吗?按下Alt+C弹出计算器,Ctrl+T显示系统时间——这些看似简单的功能背后,是80年代程序员对系统资源的极致利用。今天,我们将穿越回那个640KB内存就是奢侈品的年代,用DosBox和Masm6.15亲手实现一个真正的TSR(Terminate and Stay Resident)程序。

1. 为什么TSR是DOS时代的编程艺术

在Windows的预抢占式多任务出现前,DOS程序员们发明了TSR这种巧妙的"伪多任务"方案。一个典型的TSR程序执行流程是这样的:

  1. 程序正常启动执行
  2. 通过DOS中断将自己驻留在内存中
  3. 修改中断向量表挂钩特定事件
  4. 主程序退出但代码段保留在内存
  5. 触发事件时(如按键)执行驻留代码

这种技术催生了SideKick、Borland的Turbo系列编辑器等经典工具。理解TSR不仅能学习汇编,更能体会早期程序员在有限资源下的创造力。

注意:现代操作系统严格隔离进程内存空间,TSR技术已不再适用,但其中的中断处理、内存管理等概念依然有价值。

2. 搭建考古现场:配置Masm6.15的黄金组合

不同于简单的Hello World,TSR开发需要完整的MASM 6.15工具链。建议采用以下目录结构:

DOS_TSR_DEV
├── MASM6.15      # 编译器工具链
│   ├── BIN       # 可执行文件
│   ├── LIB       # 库文件  
│   └── INCLUDE   # 头文件
├── TSR_ASM       # 项目代码
│   ├── CALC.ASM  # 计算器TSR
│   └── CLOCK.ASM # 时钟TSR
└── UTILS         # 辅助工具

在DosBox配置文件中建议添加这些自动挂载命令:

[autoexec]
mount c D:\DOS_TSR_DEV
c:
set PATH=%PATH%;C:\MASM6.15\BIN
set LIB=C:\MASM6.15\LIB
set INCLUDE=C:\MASM6.15\INCLUDE

关键环境变量说明:

变量名 作用 典型值
PATH 可执行文件搜索路径 C:\MASM6.15\BIN
LIB 链接库文件路径 C:\MASM6.15\LIB
INCLUDE 头文件路径 C:\MASM6.15\INCLUDE

3. TSR核心机制解剖:从理论到实践

3.1 内存驻留的魔法:DOS功能调用

实现TSR最关键的两步:

; 设置程序为驻留状态
mov ax, 3100h      ; AH=31h(驻留退出) AL=返回码
mov dx, (TSR_END + 15) / 16 ; 需要保留的段落数
int 21h            ; 调用DOS中断

计算驻留内存大小的经验公式:

段落数 = (代码结束地址 - 程序起始地址 + 15) / 16

3.2 中断劫持技术详解

要让TSR响应热键,需要接管键盘中断(INT 09h)。典型流程:

  1. 保存原中断向量
  2. 安装自定义处理程序
  3. 在自定义处理程序中:
    • 调用原中断处理
    • 检查特定热键组合
    • 触发TSR功能
; 保存原中断向量
mov ax, 3509h     ; AH=35h(获取中断向量) AL=09h(键盘中断)
int 21h
mov word ptr [OLD_INT09], bx
mov word ptr [OLD_INT09+2], es

; 设置新中断向量
mov dx, offset NEW_INT09
mov ax, 2509h     ; AH=25h(设置中断向量) AL=09h
int 21h

4. 实战:编写热键弹出计算器TSR

让我们实现一个按Alt+C弹出简易计算器的TSR。完整代码框架如下:

.MODEL small
.STACK 100h
.DATA
    OLD_INT09 DD ?     ; 保存原中断向量
    CALC_FLAG DB 0     ; 计算器激活标志
    ; 其他数据定义...
.CODE
START:
    ; 初始化代码...
    jmp INSTALL_TSR

NEW_INT09 PROC FAR      ; 新键盘中断处理
    pushf
    call DWORD PTR [OLD_INT09] ; 先调用原处理程序
    
    in al, 60h         ; 读取键盘扫描码
    cmp al, 46h        ; 'C'键扫描码
    jne EXIT_INT
    mov ah, 2          ; 获取键盘状态
    int 16h
    test al, 00001000b ; 检查Alt键
    jz EXIT_INT
    
    not [CALC_FLAG]    ; 切换计算器状态
EXIT_INT:
    iret
NEW_INT09 ENDP

CALCULATOR PROC         ; 计算器界面实现
    ; 实现加减乘除逻辑...
    ret
CALCULATOR ENDP

INSTALL_TSR:
    ; 安装中断处理程序...
    mov dx, OFFSET INSTALL_TSR
    mov cl, 4
    shr dx, cl          ; 转换为段落数
    add dx, 10h         ; 安全余量
    mov ax, 3100h       ; 驻留退出
    int 21h
END START

编译这个TSR需要特殊步骤:

masm calculator.asm;
link calculator.obj;
exe2bin calculator.exe calculator.com

提示:TSR更适合编译为.COM格式,因为它从0100h开始加载,更易计算驻留大小。

5. 调试TSR的军火库:经典工具与技术

调试TSR需要特殊技巧,因为一旦驻留就无法用常规方法调试。推荐工具链:

  • DEBUG.COM :DOS自带的调试神器

    • 查看内存: d segment:offset
    • 反汇编: u address
    • 设置断点: g=start,end
  • INT 3技巧 :在TSR代码中插入 int 3 触发调试器

  • 内存查看命令

    mem /d    # 查看内存使用情况
    mem /p    # 查看驻留程序
    

常见问题排查表:

症状 可能原因 解决方案
系统崩溃 中断处理未正确保存寄存器 确保所有寄存器被保存/恢复
热键无响应 未正确检测键盘状态 检查Shift状态字节
驻留后功能异常 内存计算错误 重新计算驻留段落数
与其他TSR冲突 中断链处理不当 确保调用原中断处理程序

6. TSR进阶:从玩具到实用工具

要让TSR真正实用化,还需要考虑:

内存管理技巧

  • 使用EMS/XMS扩展内存(如果有)
  • 实现按需加载(Overlay技术)
  • 提供卸载接口
UNINSTALL_TSR:
    ; 恢复原中断向量
    mov dx, word ptr [OLD_INT09]
    mov ds, word ptr [OLD_INT09+2]
    mov ax, 2509h
    int 21h
    
    ; 释放内存块
    mov ah, 49h
    mov es, word ptr [PSP_SEG]
    int 21h
    ret

多TSR共存方案

  • 使用中断链技术
  • 实现优先级管理
  • 提供状态查询接口

在DosBox中测试不同配置:

配置项 推荐值 作用
memsize 16 模拟1MB内存(DOS常规+UMB)
cycles max 10000 控制CPU速度模拟
core dynamic 动态调整CPU周期

7. 从考古到启示:TSR技术的现代映射

虽然TSR技术已经过时,但其核心思想在现代开发中依然可见:

  • 中断处理 → 事件驱动编程
  • 内存驻留 → 后台服务/守护进程
  • 热键触发 → 全局快捷键
  • 中断链 → 中间件/Middleware

用现代Python实现类似功能:

import keyboard
import tkinter as tk

def show_calculator():
    calc = tk.Tk()
    # 计算器UI实现...
    calc.mainloop()

keyboard.add_hotkey('alt+c', show_calculator)
keyboard.wait()

比较两种实现:

特性 DOS TSR 现代实现
触发机制 硬件中断 事件循环
内存管理 手动计算 自动GC
并发处理 不可重入 多线程安全
开发效率 复杂 简单
系统影响 高风险 隔离安全

在DosBox中完整测试我们的TSR程序后,不妨思考:今天我们在容器、微服务中讨论的很多"新"概念,是否都能在40年前的这些技术中找到雏形?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值