游戏开发论坛

 找回密码
 立即注册
搜索
楼主: dreamerate

[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

 关闭 [复制链接]

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-13 19:58:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

中断处理程序
~~~~~~~~~~

本贴将深入到DOS系统内部探讨中断处理程序的内容。与其他计算机编程不一样,
中断处理程序这个名词听起来就很难懂。用最简单的话来说,中断处理程序就是对应于中
断激活的程序。

    大家可能已发现,中断处理实际上并不是件很难办的事。事实上,在某些地方中断处
理很容易管理。但是,其中仍然有些“黑洞”,一旦陷入便不能自拔。本贴的信息可让你不
致于迷失在黑洞中。

      人们谈论中断已有好多年了。当它第一次作为系统设计的主要部分而应用到计算机
上时,它就获得了不安全的名声。在早期的计算机系统上,中断常常很令人头痛,因为那时
程序员们没有处理它们的经验,并不公正地将它们视为捷径。

      长久以来,中断一直是系统程序员、各种硬件工程人员未攻克的难题,许多程序员对
此是谈虎色变。幸好,PC机为处理中断提供了一个相对宽松的环境,如果你按照一些通用
的准则编写中断处理程序的话,则你所遇到的问题也就迎刃而解。一旦你掌握了足够的经
验,你就能够毫不费力地控制中断。

    首先介绍中断。除了讨论软件中产生的中断外,还讨论了内部和外部硬件产生的
中断。在介绍这些之前,应该先考虑一下中断是怎样为你服务的。围绕着中断处理的讨论。

    让我们先开始最基本的内容——探讨什么是中断。

什么是中断?

      “中断”是一种信号,它告诉处理器已发生了某件需要特别注意的事情。它用于让处理
器集中注意力来处理某件重要的事情。如果没有中断,就必须周期性地查询每一设备,并
检查设备上是否有所需要的东西。

      如果在一个查询系统上共有60种设备,并且每检查一种设备要用1秒钟,那么,每分
钟内每台设备只能检查1次。若在这种情况需要更快速的响应,那么很显然,查询方法不
适合。使用中断的原因就在于消除查询的需要,并延缓对外部事件的服务。

      例如,当磁盘驱动器发生信号,告诉系统它准备把一个信息扇区传送到主内存时,中
断就会产生。如果处理器对中断的响应太慢,则此块被丢失,这样,强迫处理器把所进行的
一切搁到一边,立即执行中断。

      上例中的这类中断是由外部事件产生的。内部事件也能产生中断,如计算机中出现被
零除错误或程序发出指定的执行软件中断请求,包括广泛地用于每一虚拟DOS功能的
Int 21h。

      无论计算机何时收到中断信息,它都会停下自己正在进行的一切,在程序中“标记它
的位置”,并把控制权交给中断程序,然后,中断处理程序处理急待处理的事件,并随即返
回。有些处理器只提供严格限制的中断标识,并依靠中断处理程序识别中断以及随后采取
相应的处理措施。

      通过使用中断向量来缩短启用特定中断处理程序的时间,这样便可在处理器的8086
系列上更有效地处理中断。一个中断向量就是一个指向实际处理程序例程的远指针(32
位,采用偏移值:段格式);在8086系列里,RAM的头1024个字节专门用于提供256个处
理器能识别的中断向量。

      为中断处理程序编程曾经是一种多少带点神秘色彩的艺术,很少有人知道它,在一些
较旧的系统上知之者更是廖廖无几。在一些系统上,中断处理涉及精确的定时问题,以及
处理器和计算机设计的错综复杂的知识,这些知识远远超出了经典的编程员们曾涉足过
的范围。在能产生中断的系统上,多级中断出错是威协程序员们生存的祸根,因为查找错
误的途径毫无规律可循,并且几乎不可能找到。

      然而,PC机上的中断相对来说要好处理得多,原因有两方面。一方面是因为PC类是
单用户单进程的系统,另一方面其中断结构要完善得多。虽然小心谨慎是必不可少的,但
可用这种标准的中断结构来处理下述情况的中断:

      1.当中断产生时,把处理器没有自动保存的一切内容保存起来(这意味着在处理程
序的操作期间,PC机上的全部寄存器都可能会被改变;最安全的办法就是将它们全部保
存起来,但CS、IP、SS和SP除外,可将它们压入堆栈)。
      2.禁止出现可能干涉处理程序操作的所有中断。
      3.允许在处理程序的操作期间可安全地出现的中断。
      4.处理中断。
      5.把保存的处理器寄存器恢复到步骤1。
      6.重新启用中断。
      7.返回到正常的进程。

      虽然这些信息不一定能处理好中断,但它的确能引导你小心地渡过难关。
      许多人曾遇到过这种情况——串行I/O,这种情况很难处理,除非把中断处理程序与
    串行端口连接在一起。Microsoft BASIC提供了一种用于通信的内部中断处理程序,该程
    序允许进行串行I/O操作。使用C语言、Pascal或汇编语言时,必须编写自己的处理程序。

      Ctrl-Break/Ctrl-C处理程序也是一种有用的中断处理程序,对许多程序而言,Ctrl-
Break让它们处于一种糟糕的境地——不更新文件以及等等。要按正常的方式关闭此种程序,Ctrl-Break处理程序会让你的程序控制退出。

中断的工作方式
~~~~~~~~~~

    中断产生时,处理器可处于任何状态。处理器被设计成在响应中断之前,它总是能完
成进程中的任何步骤。当处理器识别了中断时,它迅速作出响应:把标志寄存器(程序状态
字)、指令指针(IP)和代码段寄存器(CS)压到堆栈上,并禁止中断。

    保存了关键机器状态信息之后,处理器在系统总线中查找一个8位数——中断请求
级(IQR)。该级能准确地识别是哪一设备发出了中断,并让处理器知道用哪一向量作出响
应。前面已解释过,中断向量是指向用于指定功能的实际处理程序例程的指针。

    8086 PC(和它的后续系列)把一个固定为8的偏移值加上中断的设备提供的数字来
确定中断信号是否已发出。例如,IRQ 0级产生Int 08h,并且IRQ第7级产生Int 0Fh(在
AT和PS/2设计中,把这一处理进行了修改,它们能识别超过8个的中断请求级,但原理
仍然相同)。

    处理器把Int号乘以4来把其偏移值保存到中断向量表(interrupt vector table)中。然
后查看段0000h以找到该向量。该向量的内容被置入CS : IP,并自动地控制处理中断的
程序(中断处理程序)第一道指令的发出。

    在处理器使用中断处理程序期间,中断处理程序便控制着该处理器。大多数处理程序
首先重新启用中断以便能服务于有更大优先权的中断。它们还保存它们使用的全部寄存
器,然后尽快地执行它们自己的操作。对于有些设备,必须传送特殊的接收信号,以便让该
设备知道它已被服务过。处理程序必须在需要的地方提供这种特殊信号。

    通常情况下,必须把中断处理程序尽可能地编写得既精简又快速,其中大多数是用汇
编语言写成的,这样可消除所有多余的开销,并确保该程序尽可能快速地运行。也可以用
C语言编写处理程序(本章列举了几个C语言的例子),但是必须用尽量少的开销来处理
关键时间(time—critical)中断。

    通过8259A可编程的中断控制器(PIC)引发的中断(IRQ产生的硬件中断)必须在处
理完毕时把一个终止中断的信号发送给PIC。中断处理完毕后,所有的中断处理程序都必
须恢复机器的状态,具体步骤是先恢复全部保存的寄存器,然后执行中断返回(IRET)指
令来把标志寄存器、CS和IP恢复到中断产生前的值。

Intel 8086系列的中断类型
~~~~~~~~~~~~~~~~

    8086微处理器系列上的中断可分为三种基本类型。这一节将分别讨论这三种中断类
型:
      ·内部硬件中断
      ·外部硬件中断
      ·软件中断

内部硬件中断
~~~~~~~~~

      在处理器中设计内部硬件中断是为了处理一些特殊的情况,诸如被零除出错或其它
一些处理器已意识到出错的情况。这些情况列于表11.1中。

内部硬件中断
~~~~~~~~~~~

(a)8086处理器硬件中断

中断级                  向里偏移值(地址)        含义
    00h                        00h                    被零除
    01h                        04h                    单步
    02h                        08h                    不可屏蔽中断
    03h                        0Ch                    断点
    04h                        10h                    溢出

(b)80286处理器硬件中断

中断级                  向里偏移值(地址)          含义
    05h                      14                     超出界限范围
    06h                      18h                    无效的操作码
    07h                      1Ch                    处理器扩展不可用
    08h                      20h                    双重异常
    09h                     2411                    段超限
    0Ah                      28h                    非法任务状态段
   0Bh                     2Ch                     不存在的段
    0Ch                      30h                    堆栈段超限
   0Dh                     34h                     通用保护故障

      不能把这些中断直接用于程序。在基本的PC机设计中,IBM重新安排了其中的一些
中断(8086/80286的最初设计中没有用到,但出现在后来的扩展版本中)来处理其它的情
况。在下代芯片(80186)问世时,冲突出现了,并且一直延续到今天,这种冲突源于8086系
列芯片的设计与IBM对中断向量的使用。出现这种情况并不是什么好事,但我们必须处
理它。表11.2列出了IBM指定的中断向量。比较表11.1和11.2,不难看出其中相冲突
的地方。

外部硬件中断
~~~~~~~~

      处理器可连接外部硬件中断来允许设备发出中断信号。早期大多数使用中断的微型
计算机就是按这种方式建成的。有两种连接方式可用:不可屏蔽的中断(NMI)和可屏蔽
的中断(INTR)。仅仅从名字上判断,应该可以关掉INTR,但不能切断NMI。
      当不想因为任何理由而终止中断时,可使用NMI中断。在一些系统上,把物理重设置
开关以线接的方式连接上NMI中断,操作员便能获知处理器的全部动向。

      把INTR中断线接到8259A PIC中可利用芯片的优先列入功能,并可在软件控制下控制中断。处理器指令能直接允许和禁止中断,并且加给PIC的指令能有选择地允许和
禁止中断。

    但是,中断是设置在硬件层上的。在某些产品中,生产厂商还设置了中断级,并且丝毫
无法改变它们。一些设置提供开关或跳转程序,它们只能在有限范围值内重新设置中断
级。

中断向量表
~~~~~~

向量         行    为
00h           被零除
01h           单步
02h           不可屏蔽中断
03h           断点
04h           溢出
05h           打印屏幕
06h           未使用
07h           未使用
08h           硬件IRQ0(计时器计时)
09h           键盘输入中断
0Ah           保留
0Bh           异步端口控制卡1(COM2
0Ch           异步端口控制卡0(COM1
0Dh           硬盘控制卡
0Eh           软盘控制卡
0Fh           打印机控制卡
10h         视频驱动程序
11h           设备配置检查
12h           内存大小检查
13h           软盘/硬盘(PC/XT)
14h           通信端口驱动程序
15h           磁盘/网络服务
16h           键盘驱动程序
17h           打印机驱动程序
18h             ROMBASIC
19h           重启动系统
1Ah           设置/读实时时钟
1Bh          Ctrl-Break处理程序
1Ch           计时器计时(用户定义)
1Dh           视频参数表
1Eh           磁盘参数表
1Fh           图形字符表(字符80h-FFh)
20h           程序终止
21h            DOS功能调度程序
22h           终止向量
23h            Ctrl-C向量
24h           关键出错向量
25h           绝对磁盘读
26h           绝对磁盘写
27h           终止并驻留
28h           DOSOK中断
2Fh           多路复用中断(见参考手册部分)
40h           软盘驱动程序(PC/XT)
41h           硬盘参数表
43h           图形字符表

软件中断
~~~~~~~~

    软件中断是这样产生的:程序发出软件中断指令给处理器,使得处理器像接收到硬件
中断一样采取行动。这种方法通常用来访问与程序无关的DOS和BIOS服务程序。根据
需要,可把这两种服务程序链接到指定的中断上,然后改变它们,并丝毫不影响调用它们
的应用程序。

中断向量
~~~~~~~

        中断向量表被保存在系统内存中最低的1024个字节中,每个中断向量占用四个字
    节,一共有256个不同的中断向量。相应功能中断处理程序的偏移值和段地址组成了每个
    四字节的项。在有些情况下,向量也包含数据值表的地址,而不是程序的地址,如Int 1Fh所指的图形字符表。

获取和设置中断向量
~~~~~~~~~~~~

        有关中断向量的所有警告会让你警觉到中断量可能具有的任何影响都有其破坏性的
    一面。设想某一程序正在改变四字节中断向量中的两个字节,那么,需要使用正在改变的
    中断向量的另一进程的中断使正在执行的用户程序暂停,并使CPU跳转到一个未完成的
    向量地址上,从而可能在内存中的任何地方不可预知地中止。这种情况常常导致“挂起”你
    的计算机,有时甚至会冲掉你的硬盘。

        这一过程是如何实现的呢? DOS是一种单任务系统,一次只能进行一种操作。但是,
    对应于硬件中断的另一种中断服务例程会简单地采取控制并让你的程序半路上接通它。
    许多TSR在被激活时就获得了控制权,并在任务完成后把中断归还给它们的初始设置,
    这种情况确实可以出现。在编程过程中,任何实际将发生的事情都能够发生;问题只在于
    它发生得早或迟。

        更为重要的是向上兼容性的问题。直接修改中断向量与后来的DOS升级版本不兼容
    (如果把OS/2看作是一种升级的话,那么也包括它)。虽然目前已能直接进行修改,但绝
    对不能在多任务系统上进行。倒是DOS提供了改变一个中断向量的安全途径—使用
    Int 21h的功能25h(设置中断向量)和35h(获取中断向量)。

        1.使用功能35h来获取当前向量值,并把此值保存起来,留待以后在链接已使用中
    断的程序以及保存此中断时使用。

        2.使用功能25h来设置中断向量。
        这一过程简单地采用了汇编语言来编写(参见如下)。

; GetSet.asm
; ----Get the Ctrl-C vector----

    mov        ah, 35h         ;Get vector
    mov        al,  23h        ;Ctrl-C
    int          21h

    mov        oldseg, es      ;Store old vector
    mov        oldoff, bx

;----Set the Ctrl-C vector----
       mov    ah, 25                 ;set vector
       mov     al, 23h               ;Ctrl-C
       mov     dx, seg c_hand
       mov     ds, dX
       mov     dx, offset c_hand
        int     21h

    无须在DOS层上设置中断。可用的高级语言服务程序有助于清晰地设置中断,并消
除它们在遇到问题时可能分散注意力。这些高级语言程序在执行Int 21h的功能25h和
35h服务时显得更方便。

    Borland C/C++提供了两种函数—getvect()和setvect(),它们在不调用DOS功能
的情况下,就能做到与DOS功能35h和25h一样的事情。在MicrosoftC/C++中,
dos_getvect和_dos_setvect函数也执行同样的操作,而在Turbo Pascal中,执行这些操作
的是GetlatVec和SetIntVec函数。

什么时候必须写一个中断处理程序
~~~~~~~~~~~~~~~~~~~~

在下述几种情况下,有必要创建自己的中断处理程序:

      ·必须捕获中断并防止程序在不正常情况下失败。编写商用程序时,决不能让用户在
        出现被零除错误或其它一些错误时“炸毁”于应用程序。应用程序必须处理出错。进一
      步地讲,若程序在执行任何“令它喜爱的”操作时,必须捕获Ctrl-C和Ctrl-Break事
      件,并处理它们,而不能让系统中断。

      ·必须链接到中断链中。在这方面的两个例子是:编写在某些固定击键上执行的TSR
      和编写希望在程序中用到的特殊定时程序。

      ·必须控制串行端口。前面曾提到,DOS并不为串行端口提供充足的服务。若想编写
        实际用的终端程序,那么,它必须具有中断驱动的、串行端口的服务例程。

      在除此之外的情况下,必须尽可能地用高级语言编写代码。如果能用高级语言编写中
断处理程序的代码,那么无论如何都得这样作,除非该中断处理程序在程序中运行得不够
快。用高级语言进行调试比用汇编语言要容易得多。若处理程序运行得不够快,可随时将
它重新进行编码。

      只要有可能,应尽量使用高级语言函数来处理中断。Borland C/C++提供的ctrlbrk
()函数可用于从高级代码模式中设置Ctrl-C中断处理程序。Microsoft C/C++提供的
UNIX兼容的signal()函数用于处理信号捕获。除了其它命令之外,QuickBASIC还提供了
用于处理事件的ON KEY和TIMER命令。Turbo Pascal能处理那些有直接插入的汇编
代码或使用Interrupt伪指令的中断。因此,应尽可能地选择能完成这项工作的高级语言。

      编写中断处理程序时,若无特殊的需要,一般不要使用DOS型的功能。DOS是不可
重入的;若DOS在进行某件事时被中断,那么当再次调用DOS功能时,会很容易锁定系
统。
      有一种方法可不调用DOS功能,即让中断处理程序做些设置进程的工作(例如把数据
复制到缓冲区内)。中断处理程序可设置一种标志,当前正在使用系统去做其它处理的程
序能识别此标志,从而可防止它可能去调用DOS功能。更透彻地讲,DOS用一些隐藏的方
法来确定DOS调用在什么时候是安全的。那些花大量的时间去猜测别人是如何执行
计算机技术的人已发现并公布了一些学习DOS所作的方法。

        首先,Int 21h功能(功能34h)通过ES:BX寄存器返回一个指针,该指针指向一个
    DOS忙碌标志,我们称此标志为InDOS标志。此标志是深藏在操作系统内核中的一个单
    字节。不管Int 21h功能何时启动,此标志都减去1;当这一功能终止时,该标志001。当
    该标志为0时,就表示没有执行任何DOS功能。

      无论什么时候按下TSR的热键,它都检查InDOS标志。若此标志非零,TSR在其自
    身内设置一热键标志。然后这样做的TSR连接时钟中断,并且每秒检查InDOS标志18.2
    次,直至该标志清除。当InDOS被清除而此热键标志还设置着的时候,TSR开始它自己的
    操作。

        这种处理虽然好,只是在命令处理器等待用户敲入命令行时,它让用户干等着。因为
    命令处理器使用DOS功能来进行命令行输入,在DOS等待字符时,InDOS标志已设置。
    很明显,DOS正处于安全的位置,如果不用这些DOS功能进行控制台I/O操作的话,那
    么,其它的操作就能中断DOS。为了允许控制台I/O操作的进行,DOS使用了另一种中断
功能—28h,当控制冶输入程序在等待输入时,它们会重复地调用这一功能。这种中断
为DOS空闲(或DOSOK)中断。

      DOS空闲中断通常执行中断返回(IRET),IRET返回控制权给控制台输入程序。如
果将TSR链接上这种中断,并注意到热键标志已打开时,那么就可以立即执行TSR。

      使用中断时,应确保遵循这样一条规则——应一直假设可以调用其它程序。例如,绝
对不能直接设置中断向量。Int 21h的功能25h就是用于这一目的的服务,并防止两种程
序在设置中断向量时出现混淆。除非编写像Ctrl-C处理程序之类的内容,否则,必须保存
初始的处理程序向量,并在完成进程时才能对它进行分支。也可以安装另一种需要激活的
处理程序。若不遵守这种简单的规则,在实际操作中就会遇到麻烦。

    程序终止时,它必须清除它曾设置的所有中断处理程序(系统自动地清除关键出错和
Ctrl-C处理程序)。例如,若编写终端程序,那么在终止此程序之前,必须恢复初始的中断
处理程序,从而防止中断出现在处理程序所在的地方。若程序将设置常驻程序,则必须使
用TSR终止,以便处理程序能永久地获得它所需的内存,并不致于被改写。

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-13 20:03:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

参考资料:《DOS程序员参考手册》第四版;英文原名为“DOS Programmer's Reference, 4th
Edition”,作者是美国的Terry Dettman及AllenL.Wyatt, Sr. 。本书是Que的保留书
目,内容完整,解释清楚,在介绍DOS编程技术的书籍中,本书是多年来最有影响、最受欢
迎的书籍之一。

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-13 20:10:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

这里是VB区,讨论这种话题好像不太适合。:)

而且DOS这种老古董也没什么好讨论的,作为WIN32的程序员,不是吗?

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-13 20:11:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

如果不怕扔鸡蛋,就继续……呵呵!反正偶是无所谓的。

248

主题

2674

帖子

2702

积分

金牌会员

Rank: 6Rank: 6

积分
2702
QQ
发表于 2006-1-14 00:41:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

dos下的hgame还是不错的

14

主题

163

帖子

178

积分

注册会员

Rank: 2

积分
178
QQ
发表于 2006-1-14 15:54:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

好象不是你写的,我只要你的感悟.
第二个问题,BiOS初始化的那些中断被放到整个内存的什么地方?
PS,连DOS都掌握不好,别提保护模式了.

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-14 17:35:00 | 显示全部楼层

Re: Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家

……在8086系列里,RAM的头1024个字节专门用于提供256个处
理器能识别的中断向量。


……汗一个……这种小学生都知道的问题。麻烦你不要发到我的贴子中来……不要自以为是,我有点怀疑你是某一个人了……

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-14 17:39:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

WIN32的PE比16BITS的DOS复杂的多,你不要以为DOS有多难。WINDOWS发展到今天。完全不是当日DOS的那种单任务、没有区分RING的、只能使用64K内存所能担任的了……你既然是搞操作系统的,建议你花时间去看看LINUX源代码或是WINDOWS2000源码吧

7

主题

229

帖子

247

积分

中级会员

Rank: 3Rank: 3

积分
247
QQ
 楼主| 发表于 2006-1-14 17:45:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

256*4=1024

实际上内存的开端1024个字节被中断向量所使用。

14

主题

163

帖子

178

积分

注册会员

Rank: 2

积分
178
QQ
发表于 2006-1-14 23:03:00 | 显示全部楼层

Re:[原创DLL]前几天我用MASM编写的Utils.dll拿出来给大家用用

我说的是BIOS的中断处理程序内存绝对位置,不是中断向量表的位置(谁都知道中断向量表在哪里).
我精通Linux 2.4.x的源代码,你以为实模式能难的倒我吗?
Ring0,Task,IDT,GDT,edc......
下面一个问题,VM86模式是模拟8086的一种模式,请设计类似NTVDM的虚拟机程序.
你这么聪明,这个不会设计不出来吧.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-24 11:34

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表