大会TSR - 我的程序崩溃,我不知道原因

时间:2012-08-22 05:12:15

标签: assembly x86 dos tsr

我正在写一个简单的TSR程序,但是我收到了错误。

我试图通过Int 90H执行它,但出于某种原因,它已经崩溃了。

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

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

你知道我的程序崩溃的原因吗?

2 个答案:

答案 0 :(得分:0)

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

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

通常应该在中断处理程序中避免

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

如果你想确保在你自己的中断处理程序中没有执行其他中断,中断处理程序开头的int 10h会阻止大多数中断,恕我直言是个好主意。请务必在cli之前sti允许中断。

答案 1 :(得分:0)

在我们使用iret指令从中断服务程序(ISR)返回之前,我们必须向“mov al,020h”+“out 20h,al”发送“中断结束”-signal(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 --------------------------
端口0020-003F - PIC 1 - 可编程中断控制器(8259A)
参见:PORT 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+ - 终止和留住居民
DX =保持驻留的字节数(最大FFF0h)
CS = PSP的分段
回报:永远不会 注意:这是一个过时的电话 从PSP中恢复INT 22,INT 23和INT 24 不会关闭任何打开的文件
对于将保持驻留的最小字节数是110h 用于DOS 3.0+的DOS 2.x和60h; DOS 1.x没有最低要求,其中 在COMMAND.COM而不是DOS内核中实现此服务 SeeAlso:INT 21 / AH = 31h

; ----------

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

------

用于设置和获取中断向量:

RBIL-> inter61b.zip-> INTERRUP.F
-------- d-2125 -------------------------------
INT 21 - DOS 1+ - 设置中断矢量
   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      处理器安装
SeeAlso:AX = 2501h,AH = 35h

-------- d-2135 -------------------------------
INT 21 - DOS 2+ - 获取中断矢量
   AH = 35h
   AL =中断号码
返回:ES:BX - >当前中断处理程序
注意:在DR DOS 5.0+下,此功能不使用任何DOS内部
     堆栈,因此可以随时调用 SeeAlso:AH = 25h,AX = 2503h

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

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

德克