汇编语言-13int指令

int指令

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

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

(1) 取中断类型码n;
(2) 标志寄存器入栈,IF=0, TF=0;
(3) CS、IP入栈;
(4) (IP)=(n*4),(CS)=(n*4+2)。

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

可以在程序中使用int指令调用任何一个中断的中断处理程序。

assume cs:code
code segment
    start:mov ax,0b800h
        mov es,ax
        mov byte ptr es:[12*160+40*2],'!'
        int 0     /*这里调用0号内存中断*/
code ends
end start

程序执行后将在屏幕中间显示一个“ ! ”,然后显示“ Divide overflow” 后返回到系统中。”!”是编程显示的,程序是有做除法,但是在结尾使用了int 0指令。CPU执行int 0指令时,将引发中断过程,执行0号中断处理程序,而系统设置的0号中断处理程序的功能是显示“Divide overflow”, 然后返回到系统。

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

一般情况下,系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用。在编程的时候,可以用int 指令调用这些子程序。当然,也可以编写一些中断处理程序供别人使用。

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

功能:求一word型数据的平方。
参数:(ax)=要计算的数据。
返回值:dx、ax中存放结果的高16位和低16位。
举例: 求2*3456^2

assume cs:code
code segment
    start:mov ax,3456    #(ax)=3456
        int 7ch    #调用中断7ch的中断过程,计算ax中的数据的平方,计算结果存在ds(高16位),ax(低16位)中
        add ax,ax    #ds:ax中的值乘以2第一步,低16位相加,如果进位则CF=1
        adc dx,dx    #dx:ax中的值乘以2第二部,高16位相加并加上CF
        mov ax,4c00h
        int 21h
code ends
end start

写中断例程分三步:

(1) 编写实现求平方功能的程序;
(2) 安装程序,将其安装在0:200处;
(3) 设置中断向量表,将程序的入口地址保存在7ch表项中,使其成为中断7ch的中断例程。

assume cs :code
code segment
start:mov ax,cs
    mov ds,ax
    mov si,offset sqr    #设置ds:si指向源地址
    mov ax,0
    mov es,ax
    mov di,200h          #设置es:di指向目的地址
    mov cx,offset sqrend-offset sqr   #设置ex为传输长度
    cld                               #设置传输方向为正
    rep movsb    #从ds:si拷贝到es:di,每拷贝1个字节,cx-1
    
    mov ax,0
    mov es,ax
    mov word ptr es:[7ch*4],200h    #设置7ch中断程序的偏移量
    mov word ptr es:[7ch*4+2],0   #设置7ch中断程序的段地址
    
    mov ax,4c00h
    int 21h
    
sqr: mul ax
    iret
sqrend: nop

code ends
end start

注意:在中断例程sqr 的最后,要使用iret 指令。用汇编语法描述, iret 指令的功能为:

pop IP    #偏移地址出栈
pop CS    #段地址出栈
popf    #标志寄存器值出栈

CPU执行int 7ch指令进入中断例程之前,标志寄存器、当前的CS和IP被压入栈中,在执行完中断例程后,应该用iret指令恢复int 7ch执行前的标志寄存器和CS 、IP的值,从而接着执行应用程序。

int指令和iret 指令的配合使用与call 指令和ret 指令的配合使用具有相似的思路。

功能:将一个全是字母,以0结尾的字符串,转化为大写。
参数: ds:si指向字符串的首地址。
应用举例:将data 段中的字符串转化为大写。

assume cs:code

data segment
    db 'conversation',0
data ends

code segrnent
  start:mov ax,data
    mov ds,ax
    mov si,0    
    int 7ch
    
    mov ax,4c00h
    int 21h
code ends
end start

安装程序

assume cs:code
code segment
  #把程序放入0:200中
  start:mov ax,cs
        mov ds,ax
        mov si,offset capital
        mov ax,O
        mov es,ax
        mov di,200h
        mov cx,offset capitalend-offset capital
        cld
        rep movsb
        
        #设置7ch中断程序的入口cs:ip
        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
        
    #字母改大写    
    capital:push cx
        push si
    change:mov cl,[si]   #把ds:si的值放入cl中
        mov ch,O    #cx高16位重置为零
        jcxz ok    #如果cx为0则跳转,字符串遍历到最后一位是0 (db '',0)
        and byte ptr [si],11011111b    #大写操作
        inc si   
        jmp short change
    ok:pop si
        pop CX
        iret
    capitalend: nop
    
code ends
end start

对int 、iret和栈的深入理解

编程:用7ch中断例程完成loop指令的功能

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

应用举例: 在屏幕中间显示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

中断程序

    lp:push bp   #bp入栈保存
        mov bp,sp  #把sp指向的栈顶给bp
        dec cx   #cx-1
        jcxz lpret   #如果cx=0则跳转
        #栈中的情况为:栈顶处是bp原来的数值,下面是se的偏移地址,再下面是s的段地址, 再下面是标志寄存器的值
        add [bp+2],bx    #修改栈中IP指向的位置,bp中为栈顶的偏移地址,所以((ss)*l6+(bp)+2)处为se的偏移地址,将它加上bx中的转移位移就变为s的偏移地址。最后用iret出栈返回,CS:IP即从标号s处开始执行指令。
    lpret:pop bp
        iret

BIOS和DOS所提供的中断例程

在系统板的ROM中存放着一套程序,称为BIOS(基本输入输出系统),BIOS中主要包含以下几部分内容。
(1) 硬件系统的检测和初始化程序;
(2) 外部中断和内部中断的中断例程;
(3) 用于对硬件设备进行I/O操作的中断例程;
(4) 其他和硬件系统相关的中断例程。

操作系统DOS也提供了中断例程,从操作系统的角度来看,DOS的中断例程就是操作系统向程序员提供的编程资源。

BIOS和DOS在所提供的中断例程中包含了许多子程序,这些子程序实现了程序员在编程的时候经常需要用到的功能。程序员在编程的时候,可以用int指令直接调用BIOS和DOS提供的中断例程,来完成某些工作。
和硬件设备相关的DOS中断例程中,一般都调用了BIOS 的中断例程。

BIOS和DOS中断例程的安装过程

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

(2) 初始化程序将建立BIOS所支持的中断向量,即将BIOS 提供的中断例程的入口地址登记在中断向量表中。注意, 对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可, 因为它们是固化到ROM中的程序, 一直在内存中存在。

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

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

BIOS中断例程应用

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

一般来说, 一个供程序员调用的中断例程中往往包括多个子程序,中断例程内部用传递进来的参数来决定执行哪一个子程序。BIOS 和DOS 提供的中断例程,都用ah来传递内部子程序的编号。

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

bh中页号的含义:内存地址空间中, B8000H~BFFFFH共32kB 的空间,为80*25 彩色字符模式的显示缓冲区。一屏的内容在显示缓冲区中共占4000 个字节。

显示缓冲区分为8 页,每页4KB(4000B) ,显示器可以显示任意一页的内容。一般情况下,显示第0页的内容。也就是说,通常情况下, B8000H~B8F9FH中的4000 个字节的内容将出现在显示器上。

编程:在屏幕的5 行12 列显示3个红底高亮闪烁绿色的’a’ 。

assume cs:code
code segment
    mov ah,2    #置光标
    mov bh,0    #第0 页
    mov dh,5    #dh中放行号
    mov dl,12    #dl 中放列号
    int 10h
    
    mov ah,9    #在光标位置显示字符
    mov al,'a'   #字符
    mov bl, 11001010b    #颜色属性
    mov bh,0    #第0页
    mov cx,3    #字符重复个数
    int 10h
    
    mov ax,4c00h
    int 21h
code ends
end

DOS中断例程应用

int 21h 中断例程是DOS 提供的中断例程,其中包含了DOS 提供给程序员在编程时调用的子程序。
int 21h中断例程的4ch号功能,即程序返回功能,如下:

mov ah,4ch    #程序返回
mov al,0    #返回值
int 21h

(ah)=4ch表示调用第21h号中断例程的4ch号子程序,功能为程序返回,可以提供返回值作为参数。

int 21h中断例程在光标位置显示字符串的功能:

ds:dx指向字符串   #要显示的字符串需用“$“作为结束符
mov ah,9    #功能号9,表示在光标位置显示字符串
int 21h

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

编程:在屏幕的5 行12 列显示字符串“Welcome to masm! ” 。

assume cs:code

data segment
    db 'Welcome to masm','$'
data ends

code segment
    start:mov ah,2    #置光标
    mov bh,0    #第0 页
    mov dh,5    #dh中放行号
    mov dl,12    #dl 中放列号
    int 10h
    
    mov ax,data
    mov ds,ax
    mov dx,0    #ds:dx指向字符串的首地址data:O
    mov ah,9
    int 21h
    
    mov ax,4c00h
    int 21h
code ends

end start

上述程序在屏幕的5行12列显示字符串“Welcome to masm!”, 直到遇见“$“(“$“本身并不显示,只起到边界的作用)。

 

点赞

Leave a Reply

Your email address will not be published. Required fields are marked *