1.       int指令

 

n       int格式: int nn为中断类型码。它的功能是引发中断过程。

n       CPU 执行int n指令,相当于引发一个 n号中断的中断过程,执行过程如下:

n       1)取中断类型码n

n       2)标志寄存器入栈,IF = 0TF = 0

n       3CSIP入栈;

n       4(IP) = (n*4)(CS) = (n*4+2)

n       从此处转去执行n号中断的中断处理程序

 

assume cs:code

 code segment

  start: mov ax,0b800h

           mov es,ax

           mov byte ptr es:[12*160+40*2],’!’

           int 0

 code ends

 end start

n       这个程序在 Windows 2000中的 DOS方式下执行时,将在屏幕中间显示一个,然后显示“Divide overflow”后返回到系统中。

n       是我们编程显示的,而,“Divide overflow”是哪里来的呢?

   我们的程序中又没有做除法,不可能产生除法溢出。

n       程序是没有做除法,但是在结尾使用了int 0指令。

n       CPU执行int 0指令时,将引发中断过程,执行 0号中断处理程序,而系统设置的 0号中断处理程序的功能是显示“Divide overflow”,然后返回到系统。

n       可见,int 指令的最终功能和call指令相似,都是调用一段程序。

n       一般情况下,系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用。

2.编写供应用程序调用的中断例程

 

n       示例一 编写、安装中断7ch的中断例程:

n       功能:求一word型数据的平方。

n       参数: (ax)=要计算的数据。

n       返回值:dxax中存放结果的高16位和低16位。

n       应用举例:求2*3456^2

assume cs:code

 code segment

 start: mov ax,3456;(ax)=3456

         int 7ch;调用中断7ch的中断例程,计算ax中的数据的平方

         add ax,ax;dx:ax存放结果,讲结果乘以2

         mov ax,4c00h

         int 21h

 code ends

 end start

n       我们要做三部分工作:

n       1)编程实现求平方功能的程序;

n       2)安装程序,我们将其安装在0:200处;

n       3)设置中断向量表,将程序的入口地址保存在7ch表项中,使其成为中断7ch的中断例程。

assume cs:code

code segment

start:mov ax,cs

      mov ds,ax

      mov si,offset sqr

 

      mov ax,0

      mov es,ax

      mov di,200h

 

      mov cx,offset sqlend-offset sqr

      cld

      rep movsb

 

      mov ax,0

      mov es,ax

      mov word ptr es:[7ch*4],200h

      mov word ptr Es:[7ch*4+2],0

 

      mov ax,4c00h

      int 21h

sqr:mul ax

    iret

sqlend:nop

 

code ends

end start

 

n       示例二 编写、安装中断7ch的中断例程:

n       功能:将一个全是字母,以 0结尾的字符串,转化为大写。

n       参数:ds:si指向字符串的首地址。

n       应用举例:

  data段中的字符转化为大写。

n       应用举例:将data段中的字符转化为大写。

     assume cs:code

     data segment

              db 'conversation',0

     data ends

     code segment

     start:  mov ax,data

               mov ds,ax

               mov si,0

               int 7ch

                 mov ax,4c00h

                  int 21h

     code ends

     end start

 

3. intiret和栈的深入理解

n       问题:用7ch中断例程完成 loop指令的功能。

n       loop s 的执行需要两个信息,循环次数和到s的位移,所以,7ch中断例程要完成loop指令的功能,也需要这两个信息作为参数。

n       我们用cx存放循环次数,用bx存放位移。

n       应用举例:在屏幕中间显示80

  assume cs:code

  code segment

  start: mov ax,0b800h

            mov es,ax

             mov di,160*12

             mov bx,offset s - offset se;设置从标号se到标号s的转移位移

             mov cx,80

       s: mov byte ptr es:[di],'!'

             add di,2

             int 7ch                           ;如果(cx)0,转移到标号s

     se:  nop

             mov ax,4c00h

             int 21h

  code ends

  end start

n       分析:为了模拟loop指令,7ch中断例程应具备下面的功能:

n       1dec cx

n       2)如果(cx)0,转到标号s 处执行,否则向下执行。

n       下面我们分析7ch中断例程如何实现到目的地址的转移:

n       1)转到标号s显然应设(CS)=标号s的段地址,(IP)=标号s的偏移地址;

n       2)那么,中断例程如何得到标号s的段地址和偏移地址呢? 分析

n       3)现在知道,可以从栈中直接和间接地得到标号s的段地址和偏移地址,那么如何用它们设置CS:IP呢? 分析

n       int 7ch引发中断过程后,进入 7ch中断例程,在中断过程中,当前的标志寄存器、CSIP都要压栈,此时压入的CSIP中的内容,分别是调用程序的段地址(可以认为是标号 s 的段地址)和int 7ch后一条指令的偏移地址(即标号se的偏移地址)。

 

 

n       可见,在中断例程中,可以从栈里取得标号s 的段地址和标号 se的偏移地址,而用标号se的偏移地址加上bx中存放的转移位移就可以得到标号s的偏移地址。

n       可以利用iret指令,我们将栈中的se的偏移地址加上 bx 中的转移位移,则栈中的se的偏移地址就变为了s的偏移地址。

n       我们再使用iret指令,用栈中的内容设置CSIP,从而实现转移到标号s处。

n       7ch中断例程如下:

   lp:     push bp

            mov bp,sp

                dec cx

                jcxz lpret

                add [bp+2],bx

   lpret: pop bp

                iret

n       因为要访问栈,使用了 bp,在程序开始处将bp 入栈保存,结束时出栈恢复。

n       当要修改栈中se的偏移地址的时候,栈中的情况为;

n       栈顶处是bp 原来的数值,下面是se的偏移地址,再下面是s的段地址,再下面是标志寄存器的值。

n       而此时,bp中为栈顶的偏移地址,所以((ss)*16+(bp)+2)处为se 的偏移地址,将它加上bx 中的转移位移就变为s的偏移地址。最后用iret出栈返回,CS:IP即从标号s处开始执行指令。

n       如果(cx)=0,则不需要修改栈中 se的偏移地址,直接返回即可。

n       CPU从标号se处向下执行指令。

 

4. BIOSDOS中断例程的安装过程

n       BIOSDOS提供的中断例程是如何安装到内存中的呢?

n       我们下面讲解它们的安装过程。

1 开机后,CPU 一加电,初始化(CS)=0FFFFH(IP)=0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条转跳指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。

2)初始化程序将建立BIOS 所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。

3 硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。从此将计算机交由操作系统控制。

4DOS 启动后,除完成其它工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。

5. BIOS中断例程应用

n       下面我们举几个例子,来看一下BIOS中断例程的应用。

 

n       int 10h中断例程是BIOS提供的中断例程,其中包含了多个和屏幕输出相关的子程序。

n       我们看一下int 10h中断例程的设置光标位置功能。

       mov ah,2

       mov bh,0

       mov dh,5

       mov dl,12

       int 10h

n       (ah)=2表示调用第 10h号中断例程的 2号子程序,功能为设置光标位置,可以提供光标所在的行号(80*25字符模式下:0~24)、列号(80*25字符模式下:0~79),和页号作为参数。

n       (bh)=0(dh)=5(dl)=12,设置光标到第0页,第5行,第12列。

n       bh中页号的含义:内存地址空间中,B8000h~BFFFFh 32K的空间,为80*25 彩色字符模式的显示缓冲区。

n       一屏的内容在显示缓冲区中共占4000个字节。

n       显示缓冲区分为8页,每页4K(≈4000),显示器可以显示任意一页的内容。一般情况下,显示第 0 页的内容。

n       也就是说,通常情况下,B8000~B8F9F中的4000个字节的内容将出现在显示器上。

 

n       再看一下int 10h中断例程的在光标位置显示字符功能。

        mov ah,9 ;置光标

        mov al,’a’       ;字符

        mov bl,7  ;颜色属性

        mov bh,0 ;0

        mov cx,3 ;字符重复个数

        int 10h

n       ah)=9 表示调用第10h号中断例程的9号子程序;

n       功能为在光标位置显示字符,可以提供要显示的字符、颜色属性、页号、字符重复个数作为参数。代码如下:

assume cs:code

code segment

   mov ah,2

   mov bh,0

   mov dh,5

   mov dl,12

   int 10h

 

   mov ah,9

   mov al ,'a'

   mov bl,11001010b

   mov bh,0

   mov cx,3

   int 10h

 

   mov ax,4c00h

   int 21h

   code ends

   end

 

 

n       int 21h 中断例程是DOS提供的中断例程,其中包含了DOS提供给程序员在编程时调用的子程序。

n       我们从前一直使用的是 int 21中断例程的4ch号功能,即程序返回功能,如下:

     mov ah,4ch ;程序返回

     mov al,0     ;返回值

     int 21h

n       我们看一下int 21h中断例程的在光标位置显示字符串的功能:

 ds:dx指向字符串    ;要显示的字符串需用“$”作为结束符

 mov ah ,9              ;功能号9,表示在光标位置显示字符串

 int 21h

(ah)=9表示调用第21h号中断例程的 9号子程序,功能为在光标位置显示字符串,可以提供要显示字符串的地址作为参数。

 

 

 

 

 

 

 

 

posted on 2009-04-06 15:00  jasonM  阅读(3509)  评论(0编辑  收藏  举报