1

我正在编写一个简单的 TSR 程序,但出现错误。

我尝试执行它,Int 90H但由于某种原因它崩溃了。

我是 TSR 的新手,所以问题可能很简单。

总回报:

;   Copy non-small letters

.model tiny
.code
    ORG 100H
start:
    push bp
    push si
    push cx
    push bx
;   save registers
    mov bp, sp
    sub sp, cx
    sub sp, 1 ; for $
    mov di, bp
    mov si, bx
copy:
    cmp [si], 'a'
    jl  bad
;   not small letter
    cmp [si], 'z'
    jg  bad
;   not small leter
;   good
    mov ax, [si]
    mov [bp], ax
    dec bp
bad:
    inc si
loop copy
    mov [bp-1],'$'
    mov ah, 09
    mov dx, di
    int 21H
install:
    mov al, 90H
    mov ah, 25H
    mov dx, offset start
    int 21H
finish: 
    pop bx
    pop cx
    pop si
    pop bp
;   ^ restore registers
    mov ah, 31
    int 21H
    iret
;   end
end start

主程序:

.model small
.stack 64
.data
    string  db  "Hey There"
.code
start:
    lea bx, string
    mov cx, 09
    int 90H
;   end
    mov ah, 4ch
    int 21H
end start

你知道我的程序为什么会崩溃吗?

4

2 回答 2

0

在使用 iret 指令从中断服务程序(ISR)返回之前,我们必须向第一个可编程中断发送带有“mov al,020h”+“out 20h,al”的“中断结束”信号(EOI)控制器(PIC 1;8259A)。

另一种方法是跳转到旧的 ISR,而不是发送 EOI,然后返回 iret。

;---------------

Ralf Browns x86/MSDOS 中断列表 (RBIL)
http://www.pobox.com/~ralf
http://www.pobox.com/~ralf/files.html
ftp://ftp.cs.cmu.edu/ afs/cs.cmu.edu/user/ralf/pub/

RBIL->inter61d.zip->PORTS.A
----------P0020003F-------------------------
PORT 0020 -003F - PIC 1 - 可编程中断控制器 (8259A)
另见:端口 00A0h-00AFh"PIC 2",INT 08"IRQ0",INT 0F"IRQ7"
....有关详细信息,请查看 RBIL..

;------------

为了成为 TSR,我们必须使用 INT 27h 来终止我们的应用程序的 ISR 部分保持驻留。

RBIL->inter61c.zip->INTERRUP.K
--------D-27---------------------------- -----
INT 27 - DOS 1+ - TERMINATE AND STAY RESIDENT
DX = 保持驻留的字节数(最大 FFF0h)
CS = PSP 段
返回:从不
注意:这是一个过时的调用
INT 22、INT 23 和从 PSP 恢复的 INT 24
不会关闭任何打开的文件DOS 2.x
将保持驻留的最小字节数为 110h,
对于 DOS 3.0+ 为 60h;DOS 1.x 没有最低要求,它
在 COMMAND.COM 而不是 DOS 内核中实现此服务
另见:INT 21/AH=31h

;----------

它认为在我们的 ISR 中使用软件中断调用不是一个好主意。所以我更喜欢直接写入视频内存,例如在屏幕的右上角写一些数字以显示当前时间。

;------

设置和获取中断向量:

RBIL->inter61b.zip->INTERRUP.F
--------D-2125---------------------------- ---
INT 21 - DOS 1+ - SET INTERRUPT VECTOR
AH = 25h
AL = 中断号
DS:DX -> 新的中断处理程序
注意:此函数优于直接修改中断
向量表,
一些 DOS 扩展程序在此设置了 API函数,因为它在 DR DOS 5.0-6.0 下
的保护模式下没有直接意义
,所以该函数不使用任何
DOS 内部堆栈,因此可以随时调用;但是,
在 Novell DOS 7.0 - DR-DOS 7.02 下,此函数不可重入。
自 1998/05/29 起,DR-DOS 7.03 不再使用任何内部堆栈和
更早地测试此函数,以允许
除了 IRET 帧之外仅使用两个字的最小堆栈使用,允许
从 INT 21h 函数调用它,特别是设备驱动程序。这
修复了 MCS SMB 客户端
Novell NetWare(新的 DOS 请求程序除外)监视
任何 INT 24 集的偏移量,如果等于启动时的值,则替换
其自己的处理程序以允许处理网络错误;这引入
了一个潜在的错误,即任何 INT 24 处理程序偏移量
恰好与 COMMAND.COM 相同的程序都不会安装其 INT 24
处理程序
另见:AX=2501h,AH=35h

--------D-2135 -------------------------------------------
INT 21 - DOS 2+ - GET INTERRUPT VECTOR
AH = 35h
AL = 中断号
返回:ES:BX -> 当前中断处理程序
注意:在 DR DOS 5.0+ 下,此函数不使用任何 DOS 内部
堆栈,因此可能随时调用
SeeAlso: AH=25h,AX=2503h

设置中断向量的另一种方法是写入向量本身的内存位置:
示例将 Timerinterrupt(8) 设置为我们的新 ISR,从标签“TIMER_INT”:

mov ax,0
mov ds,ax
cli
mov WORD PTR ds:[8*4],OFFSET TIMER_INT
mov WORD PTR ds:[8*4+2],cs
sti

短剑

于 2013-12-19T11:07:31.337 回答
0

十多年前我为 DOS 编写了一个 TSR 调试器(一种),所以我可能忘记了一些东西。

cs无论如何,您的中断处理程序除了指向您的中断处理程序的段和(显然)指向您的中断代码之外,您不得假设任何其他内容ip,这就是您所拥有的,并且您不得修改中断处理程序中的任何其他内容(除了你特别想修改)。您必须存储您使用的所有寄存器,但不能只push将它们存储到堆栈中,因为您不能假设还剩下任何堆栈。因此,请确保保留足够的内存来存储您在中断处理程序中修改的所有寄存器,并且当您保存寄存器时,请记住将其cs用作段寄存器,而不是默认的,ds也不是es,或fsgsss,因为它们都可能指向内存中的任何位置,当然不会指向为您的 TSR 保留的任何内存块。存储标志也是一个好主意。

int 21h通常应避免在中断处理程序中调用。您可以使用 BIOS 调用 ( int 10h) 或直接写入视频内存(但如果您在 TSR 中写入视频内存,请先检查视频模式)。无论如何,在 TSR 中写入显存可能会导致问题,因为您不知道当前正在运行的程序如何使用它。

如果您想确保在您自己的中断处理程序期间没有执行其他中断,那么在您的中断处理程序cli开始时会阻止大多数中断,恕我直言是个好主意。sti请记住在之前允许中断iret

于 2012-08-25T13:24:48.597 回答