终止及常驻程式

终止及常驻程式 （Terminate and stay resident，缩写为TSR），简称常驻程式，是DOS系统下特殊的计算机程序，此程式利用DOS的系统呼叫，将电脑控制权交给操作系统，仿佛程式已经结束。但程式仍保留在电脑内存中，可以通过硬件或软件中断重新唤醒它。该技术某部分克服了DOS同一时间只能执行一个任务（Task）的限制。TSR是DOS特有的程式，不会在Windows系统中执行。

常驻程式中有些是工具软件，使用者在日常使用电脑时，可能每天会用热键多次呼叫工具软件。像Borland公司的SideKick就是早期流行的应用软件。有些常驻程式则是操作系统不直接支援的硬件装置驱动程式。

## 使用TSR

通常在DOS中，任何指定时间只能执行一个程式。要停止执行，它将使用系统呼叫 INT 21h/4Ch将控制权交回给DOS shell程式COMMAND.COM。然后将程式使用的内存和系统资源标示为未使用。事实上，这使得无法重新启动程式的某些部分而不必从头开始重新载入整个程式。但是，如果程式以系统呼叫INT 27h或INT 21h/31h结尾，则操作系统不会重用程式暂存器的特定部分。

原本呼叫INT 27h被称为“停止但仍驻留”，因此名称为“ TSR”。使用此呼叫，程式最多可占用其内存64 KB。MS-DOS 2.0版引入了改进的呼叫INT 21h/函数31h（“保留程式”），该呼叫拿掉了此限制，并允许程式返回一个返回码。在进行此呼叫之前，程式可以安装一个或多个指向其自身的中断处理程式，以便可以再次呼叫它。安装硬件中断向量可使此类程式对硬件事件做出反应。安装软件中断向量可使当前执行的程式呼叫它。安装计时器中断处理程式可使TSR定期执行（请参阅ISA）和可编程间隔计时器。

使用中断向量的典型方法包括读取其当前值（位址），将其储存在TSR的储存空间中以及安装指向其自身程式码的指标。在TSR接收到中断并完成其处理之前或之后，将呼叫储存的位址，事实上形成了中断处理程式的单连结列表，也称为中断服务程式（ISR）。安装ISR的过程称为连结或hooking中断（或中断向量）。

通过连结中断向量，TSR程式可以完全控制电脑。TSR可以具有以下两种行为之一：

- 通过不呼叫先前已更改相同中断向量的其他TSR，来完全控制中断。
- 通过呼叫旧的中断向量与其他TSR串连。这可以在他们执行实际程式码之前或之后完成。这样，TSR可以形成一系列程式，其中每个程式都呼叫下一个程式。

大多数DOS 电脑病毒和其他恶意软件都使用暂停并驻留方法，这些方法可以控制PC或使其处于后端。该恶意软件将在执行时感染可执行档（.EXE或.COM），并在打开资料档时对磁盘读写或执行档案做出反应。

DOS本身的某些部分（尤其是在DOS 5.0及更高版本中）使用相同的技术来执行有用的功能，例如DOSKEY命令列编辑器和各种其他可安装的工具程式，这些工具程式是通过在命令列上执行它们来安装的（通常是从AUTOEXEC .BAT或`INSTALL`从CONFIG.SYS内部执行），而不是通过`DEVICE`在CONFIG.SYS中的语法将它们作为装置驱动程式载入。

TSR程式可以随时被载入。有时会在操作系统启动后透过AUTOEXEC.BAT批次处理档中来载入，也可以根据使用者的要求载入（例如，Borland的Sidekick和Turbo Debugger，Quicken的QuickPay或FunStuff软件的Personal Calendar）。正如“ TSR”所暗示的那样，这些程式将在执行其他程式时保持驻留在内存中。它们中的一些没有办法从内存中将自身卸载，因此呼叫TSR意味着程式将保留在内存中，直到重新启动电脑为止。但是，可以使用MARK.EXE/RELEASE.EXE搭配TurboPower Software 或 soft reboot TSRs等工具程式从外部进行卸载。它们将被特定的键组合触发，然后释放在它们之后载入的所有TSR。由于ISR链是单个连结的，因此没有发现前一个处理程式的位址的方法（除了尝试回溯中断炼之外），或通知其前任它需要更新其“要跳转到的下一个位址”。不要指向要删除自身的TSR，以便为了安全地卸载链中间的TSR，在大多数情况下，必须在内存中保留存根，从而导致内存碎片。这产生了诸如TesSeRact和AMIS之类的TSR合作架构。

## 中断共享

为了处理共享相同中断的许多TSR程式的问题，Ralf D. Brown提出了一种称为“轮流多路中断规范”（AMIS）的方法，作为对以前通过INT 2Fh提供的服务的改进。AMIS提供了以受控方式共享软件中断的方法。它以IBM的中断共享协定为模型，该协定最初是为共享x86处理器的硬件中断而发明的。AMIS服务可通过Int 2Dh获得。

该提案在当时未受到程序员的广泛关注。它与其他几个复杂程度各异的竞争规范并存。

## 缺点

尽管TSR程式对克服DOS的限制非常有用，甚至是必不可少的，但它在制造麻烦方面享有盛誉。许多程式以各种明文或无规范的方式有效劫持了操作系统，当与特定应用程序或其他TSR一起使用时，通常会导致系统在启动或停用时当机。如上所述，某些电脑病毒和其他恶意软件被编码为TSR，因此存在一定的麻烦。此外，DOS系统中的所有程式程式码，甚至那些具有大量物理RAM的程式码，都必须载入到前640KB的RAM中（常规内存）。TSR也不例外，它占用了640 KB的块，因此应用程序无法使用这些块。这意味着编写一个TSR是一个挑战，要使其达到最小尺寸，并检查它与不同供应商的许多软件产品的相容性-这通常是一项非常令人沮丧的工作。

在1980年代末期和1990年代初，许多PC平台上的电视游戏都打破了这一限制，并为TSR（甚至是CD-ROM驱动程式之类的基本驱动器）留下了越来越少的空间，并进行了整理，以便有足够的可用RAM执行这些游戏在保留必要的TSR的同时，变成了一种黑色艺术。许多游戏玩家都有几个启动分割区具有针对不同游戏的不同配置。在更高版本的MS-DOS中，“启动选单”命令搞允许通过单个启动磁盘选择各种配置。在1990年代中期到后期，尽管仍然为DOS编写许多游戏，但通过将游戏资料和/或程式程式码的部分放在前1 MB内存之上并使用640 KB以下的程式码，最终克服了640 KB的限制。（使用DOS扩展器的方法）访问扩展的内存，并将程式码交换为最低的1 MB RAM作为一层覆盖。因为具有许多覆盖层的程式设计本身就是一个挑战，所以一旦程式太大而无法完全容纳大约512 KB，几乎总是使用第三方DOS扩展器来实现扩展内存，该扩展器实作了VCPI或DPMI，因为当x86处理器从真实模式切换到保护模式时，访问1 MB边界以上的内存变得更加容易和方便，并且可以在该区域中执行程式码。但是，由于DOS和大多数DOS程式以真实模式执行（VCPI或DPMI通过在两种模式之间来回切换，使得受保护模式程式对于DOS和系统的其余部分而言看起来像真实模式程式），因此，DOS TSR和装置驱动程式也以真实模式执行，因此，只要有人获得控制，DOS扩展器就必须切换回真实模式，直到放弃控制，这会造成时间损失（除非他们使用诸如DPMS 或 CLOAKING之类的技术）。

## 回归

随着扩展内存板（尤其是Intel 80386处理器）在1980年代下半年的到来，使用640 KB以上的内存来载入TSR成为可能。这需要复杂的软件解决方案，称为扩展内存管理器。一些内存管理器QRAM和Quarterdeck的QEMM，Qualitas的386MAX，康柏的CEMM，后来微软的EMM386。可用于载入640 KB以上的TSR的储存区称为“ 上层内存”（UMB）并将程式载入到其中被称为载入上层内存。后来，内存管理器开始包括一些程式，这些程式试图自动确定如何在低内存和高内存之间最佳地分配TSR（Quarterdeck的Optimize或Microsoft的MemMaker），以尝试最大程度地提高底层640 KB内存的利用率和可用空间。

## 灭亡

随着使用DOS扩展器的游戏的发展（早期的例子是Doom）绕过了640 KB的障碍，许多与TSR相关的问题都消失了，并且Microsoft Windows尤其是Windows 95的广泛采用（随后是Windows 98）–这使得大多数TSR变得不必要，并且某些TSR不相容-尽管Win16应用程序可以执行类似TSR的技巧，例如修补中断描述表（IDT），因为Windows允许，但TSR逐渐变得过时了。由于多工操作系统（例如Windows Vista，Windows 7，Mac OS X和Linux提供了多个程式和装置驱动程式可以同时执行的功能，而无需特殊的程式设计技巧，而现代的受保护内存概念使核心及其模组专门负责修改中断表。

## 外部链接

- An early TSR
- comp.os.msdos.programmer FAQ – How can I write a TSR (Terminate-and-Stay-Resident) utility?
- The Alternate Multiplex Interrupt Specification (AMIS), v.3.5
- AMISLIB – a function library to write self-highloading, removable TSRs in assembler
- A to Z of C ; a free book on DOS programming in C; Chapter 27 – (80 KB)
- IBM's Interrupt-Sharing Protocol, zip archive, 6.5 KB (Simtel)