Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 帮助在NASM汇编for DOS中编写TSR程序_Assembly_Dos_Nasm_Interrupt_Tsr - Fatal编程技术网

Assembly 帮助在NASM汇编for DOS中编写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

我一直在尝试在汇编(16位)中为MS-DOS编写TSR(终止驻留)程序(一般)。我读过维基百科的一页 在TSR上,还有一个专门在DOS中使用它的页面(但它似乎是在用C来教它,而不是直接用汇编)。我看了一个有大量DOS中断文档的站点,找到了另一个与TSR程序最相关的站点。我不能发布所有的链接,因为作为一个新用户,我可以在一篇文章上有多达2个超链接

所以,我尝试在NASM中以实模式平面模型(.COM文件格式)编写一个(看起来)非常简单的TSR程序。代码如下:

[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:…]
    更简单(而且编码更短)。但是你的方法也很有效

  • 您可以将初始化处理(在常驻安装的处理程序中不需要)放在程序映像的末尾。这是TSR大小的一个微不足道的优化

  • 要计算驻留进程的大小,请使用NASM标签。要允许计算段落长度所需的移位(或除法)操作,请仅使用标签的增量。delta(差)是NASM的标量值,因此可以在计算中使用。(非struc)标签本身不是标量

  • 下面是一个使用所有这些的示例:

            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]
    ,因为中断共享协议头不允许far
    jmp
    操作码。有关中断共享协议头,请参阅。您没有执行中断多路复用。我的评论是在你提出的代码的背景下进行的。是的,当我说修改JMP,放入一个虚拟JMP,简单地修改段和偏移量。你的方法就是我要做的,在MASM中,你可以使用ORG来备份位置计数器,并在那里放置一个带有类型的标签。@Michael Petch:是的,我误读了,认为你的意思是另一种方式,即
    db 0EAh
    \
    dw 0,0
    。是的,我没有使用任何IISP或AMI,只是说明实际程序可能需要间接跳转。(另外,我没有做的事情是优化大小和行为,比如从偏移量50h开始重新使用PSP的一部分,为驻留部分分配一个新块,释放环境块,重新定位初始化过程,或释放过程的文件句柄。请参阅以了解其中的大部分。)@迈克尔·佩奇:你可以在PSP:5Ch上重复使用内存,以后也可以使用FCB,只是不能在PSP的两个特定“默认FCB”插槽中使用FCB。如果我记得,打开第一个默认FCB实际上覆盖了第二个默认FCB的一部分;希望同时使用这两种方法的程序需要将它们复制到内存中的其他位置。