Assembly 帮助在NASM汇编for DOS中编写TSR程序
我一直在尝试在汇编(16位)中为MS-DOS编写TSR(终止驻留)程序(一般)。我读过维基百科的一页 在TSR上,还有一个专门在DOS中使用它的页面(但它似乎是在用C来教它,而不是直接用汇编)。我看了一个有大量DOS中断文档的站点,找到了另一个与TSR程序最相关的站点。我不能发布所有的链接,因为作为一个新用户,我可以在一篇文章上有多达2个超链接 所以,我尝试在NASM中以实模式平面模型(.COM文件格式)编写一个(看起来)非常简单的TSR程序。代码如下:Assembly 帮助在NASM汇编for DOS中编写TSR程序,assembly,dos,nasm,interrupt,tsr,Assembly,Dos,Nasm,Interrupt,Tsr,我一直在尝试在汇编(16位)中为MS-DOS编写TSR(终止驻留)程序(一般)。我读过维基百科的一页 在TSR上,还有一个专门在DOS中使用它的页面(但它似乎是在用C来教它,而不是直接用汇编)。我看了一个有大量DOS中断文档的站点,找到了另一个与TSR程序最相关的站点。我不能发布所有的链接,因为作为一个新用户,我可以在一篇文章上有多达2个超链接 所以,我尝试在NASM中以实模式平面模型(.COM文件格式)编写一个(看起来)非常简单的TSR程序。代码如下: [BITS 16] [ORG 0x010
[BITS 16]
[ORG 0x0100]
[SECTION .text]
Start:
; Get current interrupt handler for INT 21h
mov AX,3521h ; DOS function 35h GET INTERRUPT VECTOR for interrupt 21h
int 21h ; Call DOS (Current interrupt handler returned in ES:BX)
mov WORD [v21HandlerSegment],ES ; Store the current INT 21h handler segment
mov WORD [v21HandlerOffset],BX ; Store the current INT 21h handler offset
; Write new interrupt handler for INT 21h
mov AX,2521h ; DOS function 25h SET INTERRUPT VECTOR for interrupt 21h
mov DX,TSRStart ; Load DX with the offset address of the start of this TSR program
; DS already contains the segment address, it is the same as CS in this .COM file
int 21h ; Override the INT 21h handler with this TSR program
; The TSR program will be called even when this portion uses INT 21h to terminate and stay resident
mov AX,3100h ; DOS function TSR, return code 00h
mov DX,00FFh ; I don't know how many paragraphs to keep resident, so keep a bunch
int 21h ; Call our own TSR program first, then call DOS
TSRStart:
push WORD [v21HandlerSegment] ; Push the far address of the original
push WORD [v21HandlerOffset] ; INT 21h handler onto the stack
retf ; Jump to it!
[SECTION .data]
v21HandlerSegment dw 0000h
v21HandlerOffset dw 0000h
当我组装它并在DOS内执行时,它不会返回DOS提示符,而是挂起系统(除了硬件光标在最后一个提示符下闪烁外,不会发生任何活动)。我猜内存垃圾可能正在执行,但你明白了
请任何人帮助找出这段代码的问题所在和/或提供在DOS中编码TSR的一般建议?提前谢谢,非常感谢您的帮助 我明白了。在查看了更多的源代码后,我发现以下代码:
push WORD [v21HandlerSegment] ; Push the far address of the original
push WORD [v21HandlerOffset] ; INT 21h handler onto the stack
必须是这样的:
push WORD [CS:v21HandlerSegment] ; Push the far address of the original
push WORD [CS:v21HandlerOffset] ; INT 21h handler onto the stack
push DS
push CS
pop DS
; Memory references....
pop DS
因为这些内存引用是从数据段引用的,而数据段不是从TSR的调用者设置的。所以基本上我是在引用其他数据块中的数据
这也可以通过将CS放入DS(然后将DS的原始值放回)来实现,如下所示:
push WORD [CS:v21HandlerSegment] ; Push the far address of the original
push WORD [CS:v21HandlerOffset] ; INT 21h handler onto the stack
push DS
push CS
pop DS
; Memory references....
pop DS
cs:
段覆盖从通用中断处理程序中访问TSR的数据,因为ds
值是任意用户寄存器retf
跳转。执行jmp far[cs:…]
更简单(而且编码更短)。但是你的方法也很有效 cpu 8086
bits 16
org 256
start:
jmp init
align 4
int21old:
dd 0
int21handler:
jmp far [cs:int21old]
end_of_resident:
init:
mov ax, 3521h
int 21h
mov word [int21old + 2], es
mov word [int21old], bx
mov ax, 2521h
mov dx, int21handler
int 21h
mov ax, 3100h
mov dx, (end_of_resident - start + 256 + 15) >> 4
int 21h
大小计算计算两个标签的增量,在进程的PSP中加256(与
org256
相同),再加15使移位除法向上取整,然后向下移动到一定数量的段落。我是不是刚输入了一个时间扭曲并压缩回20年?@Keith Yep。别以为我是在用这门语言编写代码(我也编写Java代码),我只需要知道如何在汇编中编写TSR代码以供演示+我为此付出了代价!我是投票人。您还可以在中断处理程序中编码一个伪JMP ptr16:ptr16,并使用init
中的自修改代码来修改JMP的段和偏移量。然后,当发生中断时,跳转到的地址在指令中进行编码,而不是要求从另一个内存位置读取jmp地址。当关联的缓存线无效时,将有一次命中。@Michael Petch:如果您确实想走这条路线(自修改代码),可以让NASM encodejmp 0:0
,然后在跳转指令后立即添加一行,如int21old:eq$-4
。但是,如果您想向TSR添加IBM中断共享协议(或完整AMIS)支持,则需要使用jmp far[mem]
,因为中断共享协议头不允许farjmp
操作码。有关中断共享协议头,请参阅。您没有执行中断多路复用。我的评论是在你提出的代码的背景下进行的。是的,当我说修改JMP,放入一个虚拟JMP,简单地修改段和偏移量。你的方法就是我要做的,在MASM中,你可以使用ORG来备份位置计数器,并在那里放置一个带有类型的标签。@Michael Petch:是的,我误读了,认为你的意思是另一种方式,即db 0EAh
\dw 0,0
。是的,我没有使用任何IISP或AMI,只是说明实际程序可能需要间接跳转。(另外,我没有做的事情是优化大小和行为,比如从偏移量50h开始重新使用PSP的一部分,为驻留部分分配一个新块,释放环境块,重新定位初始化过程,或释放过程的文件句柄。请参阅以了解其中的大部分。)@迈克尔·佩奇:你可以在PSP:5Ch上重复使用内存,以后也可以使用FCB,只是不能在PSP的两个特定“默认FCB”插槽中使用FCB。如果我记得,打开第一个默认FCB实际上覆盖了第二个默认FCB的一部分;希望同时使用这两种方法的程序需要将它们复制到内存中的其他位置。