【汇编】TSR内存驻留程序实现与删除及热键设置——以实现时钟为例
最近完成了一个关于时钟中断驻留的汇编大作业,对于TSR很是感兴趣,查阅了不少资料,发现现在很少相关的内容资料。尤其是TSR删除这一块几乎找不到在低的水平完全正确的做法,下面我对于TSR的删除我会介绍一种几乎小程序可以完成的方法。当然,标题中的TSR实现,热键设置我也会一一介绍。
一、TSR的介绍(对TSR的基本概念已了解的朋友可以直接跳过第一部分):
先介绍下TSR内存驻留程序(或称中断驻留程序)即Terminate and Stay Resident Program,,缩写为TSR。这种程序加载进内存,,执行完成后,,就驻留在内存里,,当满足条件时(例如热键启动等),调到前台来执行。
程序常驻内存的目的有两个:第一,,对操作系统或BIOS 进行某些修改或补充, 比如转入用户编写的必须恒起作用的中断处理程序;第二,,解决PC DOS 不能实现多任务处理的问题,,例如在运行其他程序的过程中,定时地在屏幕上闪现一些日历、时间和其他提示信息。
二、TSR的基本格式
下面我先给出TSR程序的一般设计格式:
codes segment
assume cs:codes,ds:codes
org 100h
start:
jmp install
;;此处定义需要用到的数据
;;例: flag dw 0
subprogram:
;;此处为要驻留入内存的程序(称为驻留部分)
install:
;;此处为将上面驻留部分驻留入内存的代码(称为暂驻部分)
codes ends
end start
(1)我们需要注意到TSR的代码中只有一个段(code段),而“数据段”被搬到 jmp install 之后,这是为了减少程序驻留时所需的内存——当在同一个段时,我们至多需要占用64K的内存;而多了一个数据段,为了保证驻留部分全部被驻留进内存,我们可能需要占用128K的内存,这明显是对空间的浪费。
(2)org 100g 的作用是强制使得 start 的偏移为0100h,其实这个语句会对我们后面的暂留部分计算驻留区大小有帮助,具体作用我们留到下面解释。
三、暂驻部分程序的设计
由于暂驻部分较为简单,下面我们先来解决程序的暂驻部分。暂驻程序主要完成两种工作:(1)如何使DOS再次执行常驻内存的驻留部分,这个我们会通过修改相关中断向量来完成,如int 1ch,int 09h等;(2)驻留程序的驻留及暂驻程序的结束,这个我们可以通过int 21h的31h子功能或int 27h来实现(下面我们只介绍int 21h的31h子功能)。因此,暂驻部分可以抽象为以下过程:
(1)取中断向量
(2)保存旧的中断向量
(3)设置新的中断向量
(4)调用中断(int 21h的31h子功能)使驻留程序驻留并结束暂驻程序
我们下面以时钟程序(显示系统时间)为例,我们将会用到以下DOS中断:
INT | AH | 功能 | 调用参数 | 返回参数 |
21H | 25H | 设置中断向量 | DS:DX=中断向量,AL=中断类型 | 无 |
21H | 31H | 结束并驻留 | AL=返回码,DX=驻留区大小 | 无 |
21H | 35H | 取中断向量 | AL=中断类型 | ES:BX=中断向量 |
我们再介绍一下时钟程序常用的一个中断接口(我们将用来设置,调用我们驻留程序的“窗口”)int 1ch——在系统定时器(中断类型为08h)的中断处理程序中,有一条中断指令int 1ch,时钟中断每发生一次(约每秒18.2次)都要嵌套调用一次中断类型1ch的处理程序。简而言之,就是int 1ch会以每秒18.2次的频率被系统自动调用,利用这个机制,我们可以通过在每次调用int 1ch时,取出系统时间并显示来完成时钟设计。以下我先给出暂驻部分的代码:
codes segment
assume cs:codes,ds:codes
org 100h
start:
jmp install
OLD1C DW 2 DUP(?)
newint1c:
iret ;;此处为要驻留入内存的程序(称为驻留部分)
install:
push cs
pop ds
mov ah,35h
mov al,1ch
int 21h ;;取旧的int1c向量并保存
mov