正在加载……
专注、离线、切勿分心
int 指令
格式: int n ,n为中断类型码
功能:引发中断过程
1、取中断类型码 n;
2、标志寄存器入栈,IF=0,TF=0;
3、CS、IP 入栈;
4、(IP)=(n*4),(CS)=(n*4+2)
assume cs:code
code segment
start:        mov ax , 0b800h
        mov es , ax
        mov bx , 72ch
        mov byte ptr es:[bx] , '!'    ; 输出显示区第12行显示一个字符 !
        mov byte ptr es:[bx+1] , 2
        int 0    ; 调用 0 号中断
code ends
end start

程序执行到 int 0 就去调用0号中断,0号中断的中断服务程序在前面被改写了
中断处理程序简称中断例程




编写供应用程序调用的中断例程
编写、安装中断 7ch 的中断例程,功能:求一 word 型数据的平方
1、编写实现求平方功能的程序;
2、安装程序,我们将其安装在 0:200 处;
3、设置中断向量表,将程序的入口地址保存在 7ch 表项中,使其成为中断 7ch 的中断例程;
编写、安装中断 7ch 的中断例程,功能:将一个全是字母,以 0 结尾的字符串,转化为大写
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 sqrend - 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                    ; 相当于 pop IP  pop CS popf
sqrend:        nop
code ends
end start


assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset capital
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset capitalend - offset capital
        cld
        rep movsb

        mov ax , 0
        mov es , ax
        mov word ptr es:[7ch*4] , 200h
        mov word ptr es:[7ch*4+2] , 0

        int 7ch

        mov ax , 4c00h   ; 如果中断程序中有这段程序这里就可以不加,如果中断程序中是iret,这里就要加上;
        int 21h   ; 不然无法返回dos输入命令,这里和中断程序都加上这段也可以


capital:        jmp short change
        db 'conversation' , 0
change:        mov ax , cs
        mov ds , ax
        mov si , 202h
        mov ax , 0b800h
        mov es , ax
        mov di , 7c6h      ; 具体在显示缓冲区的显示位置偏移
s:        mov cl , [si]
        mov ch , 0
        jcxz return
        and byte ptr [si] , 11011111b
        mov cl , [si]
        mov es:[di] , cl
        mov byte ptr es:[di+1] , 2
        inc si
        add di , 2
        jmp short s

return:        iret   ;  这里要写上中断返回或者 mov ax , 4c00h  int 21h  返回dos,不然执行后程序无法输入,因为执行完中断CS:IP接着向下去执行了;
capitalend:        nop

code ends
end start



这段程序重新安装7ch处的中断程序,在以后执行7ch中断的时候执行这段程序

assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset capital
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset capitalend - offset capital
        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 

capital:        push ds    ; 中断用到的寄存器,要先进栈保存,保持中断后的一致性
        push si
change:mov cl , [si]
        mov ch , 0
        jcxz ok
        and byte ptr [si] , 11011111b
        inc si
        jmp short change
ok:        pop si
        pop ds
        iret
capitalend:        nop

code ends
end start
测试代码

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










对 int 、iret 和栈的深入理解
重写 7ch 中断,实现 loop 跳转 测试代码
assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset lp
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset lpend - offset lp
        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

lp:        push bp         ; 下面要用到bp,所以这里先保存进入中断前的bp
        mov bp , sp      
 ; 不能直接对sp修改,会导致程序崩溃,所以要访问栈中数据只能用这种方式
        dec cx
        jcxz lpret
        add [bp+2] , bx      ; bp的值是sp的,所以[bp+2]得到的是ss:sp+2,也就是中断压栈的ip的值,为int 7ch下一条指令(nop)的位移,+bx ->IP偏移到标号 s ;
; 如果寄存器相对寻址 寄存器是bp的话,段寄存器就是ss
lpret:        pop bp     ; 恢复bp
        iret         ; 中断返回,恢复CS:IP
lpend:        nop
code ends
end start
assume cs:code
code segment
start:        mov ax , 0b800h
        mov es , ax
        mov di , 160*12
        mov bx , offset s - offset se       ; 这个负偏移中断要用到来修改ip的值指向标号s:
        mov cx , 80
s:        mov byte ptr es:[di] , '!'    ; 循环打印 ! 
        mov byte ptr es:[di+1] , 2     ; 设置颜色为绿色
        add di , 2
        int 7ch          ; 设置7ch中断例程序,实现 loop s 功能
se:        nop
        mov ax , 4c00h
        int 21h
code ends
end start


   为了模拟loop,中断就要能 dec cx  , 如果(cx)≠0,转到标号s处执行,否则向下执行。这里的bx就是来记录这个负位移,中断靠这个实现向上转移;
   发生中断的时候,最后进栈的是CS、IP,这个CS就是标号s的段地址,IP就是中断下一条指令的偏移;可以在中断例程中修改这个值实现 loop s 的功能。
   中断程序中,用bp来保存栈顶sp,进栈后+2就得到中断最后进栈的IP,与bx相加就是s的偏移
 






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

     操作系统 DOS 也提供了中断例程,从操作系统的角度来看,DOS 的中断例程就是操作系统向程序员提供的编程资源。BIOS 和 DOS 在所提供的中断例程中包含了许多子程序,这些子程序实现了程序员在编程的时候经常需要用到的功能。程序员在编程的时候,可以用 int 指令直接调用 BIOS 和 DOS 提供的中断例程,来完成某些工作。

     和硬件设备相关的 DOS 中断例程中,一般都调用了 BIOS 的中断例程。





BIOS 和 DOS 中断例程的安装过程
     
BIOS 和 DOS 提供的中断例程在装到内存中的过程:
1、开始后,CPU 一加电,初始化(CS)=0FFFFh,(IP)=0,自动从 FFFF:0 单元开始执行程序。FFFF:0 处有一条跳转指令,CPU执行该指令后,转去执行 BIOS 中的硬件系统检测和初始化程序。
2、初始化程序将建立 BIOS 所支持的中断向量,即将 BIOS 提供的中断例程的入口地址登记在中断向量表中。对于 BIOS 所提供的中断例程,只需将入口地址登记在中断向量表中即可,因为它们是固化到 ROM 中的程序,一直在内存中存在。
3、硬件系统检测和初始化完成后,调用 int 19h 进行操作系统的引导。从此将计算机交由操作系统控制。
4、DOS 启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。


我们不可以编程改变 FFFF:0 处的指令,因为这个地址在系统 BIOS 的地址范围内,这里存放一条跳转指令,跳到系统 BIOS 中真正的启动代码处。
     Shadow RAM也称为“影子”内存。它是为了提高系统效率而采用的一种专门技术。 Shadow RAM所使用的物理芯片仍然是CMOS DRAM(动态随机存取存储器)芯片。Shadow RAM 占据了系统主存的一部分地址空间。其编址范围为C0000~FFFFF,即为1MB主存中的 768KB~1024KB区域。这个区域通常也称为内存保留区,用户程序不能直接访问。 Shadow RAM的功能是用来存放各种ROM BIOS的内容。或者说Shadow RAM中的内容是ROM BIOS的拷贝。因此也把它称为ROM Shadow(即Shadow RAM的内容是ROM BIOS的“影 子”)。 在机器上电时,将自动地把系统BIOS、显示BIOS及其它适配器的BIOS装载到Shadow RAM 的指定区域中。由于Shadow RAM的物理编址与对应的ROM相同,所以当需要访问BIOS时, 只需访问Shadow RAM即可,而不必再访问ROM。
     通常访问ROM的时间在200ns左右,而访问DRAM的时间小于100ns(最新的DRAM芯片访问时 间为60ns左右或者更小)。
     // 只有安装了扩展内存(系统配置640KB以上的RAM内存)才能使用影子内存技术;768KB~1024KB区域为影子区






BIOS 中断例程应用
      int 10h 中断例程是 BIOS 提供的中断例程,其中包含多个和屏幕输出相关的子程序。一般来说,供程序员调用的中断例程中往往包含多个子程序,中断例程内部用传递进来的参数决定执行哪一个子程序。BIOS 和 DOS 提供的中断例程,都用 ah 来传递内部子程序的编号。
// int 10h 中断例程的设置光标位置功能。
mov ah , 2      ; 置光标
mov bh , 0      ; 第0页
mov dh , 5      ; dh 中放行号
mov dl , 12     ; dl 中放列号
int 10h
10h 号中断的2号设置光标位置功能不会自动偏移光标,所以必须每次dl+1
// int 10h 中断例程的光标位置显示字符功能
mov ah , 9          ; 光标位置开始显示字符
mov al , 'a'         ; 字符
mov bh , 0         ; 第0页
mov bl , 7          ; 颜色属性
mov cx , 3         ;字符重复个数
int 10h
(ah)=2表示调用第10h号中断例程的2号子程序,功能为设置光标位置,可以提供光标所在行号(80*25字符模式下:0~24)、列号(80*25字符模式下:0~79),和页号作为参数。

(bh)=0,(dh)=5,(dl)=12,设置光标到第0页,第5行,第12列
bh中的页号的含义:内存地址空间中,B8000h~BFFFFh 共32K的空间,为80*25彩色字符模式的显示缓冲区。一屏的内容在显示缓冲区中共占 4000 个字节。
显示缓冲区为8页,每页4K,显示器可以显示任意一页的内容,显示第0页的内容就是显示B8000~B8F9F中的4000个字节的内容将出现在显示器
(ah)=9 表示调用第 10h 号中断例程的9号子程序,功能为在光标位置显示字符,可以提供要显示的字符、颜色属性、页号、字符重复个数作为参数。


;编程:在屏幕的第12行40列显示3个红底高亮闪烁绿色的'a'
assume cs:code
code segment
        mov ah , 2
        mov bh , 0
        mov dh , 12
        mov dl , 40
        int 10h

        mov ah , 9
        mov al , 'a'
        mov bh , 0
        mov bl , 11001010b   
        mov cx , 3
        int 10h

        mov ax , 4c00h
        int 21h
code ends
end

效果是aaa一直在闪烁,事先设置好光标,中断执行完后光标转到下一行,link的l那,可以写东西覆盖






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      

在屏幕中间显示字符串 "Welcome to masm!"

assume cs:code
data segment
        db 'Welcome to masm!' , '$'     ; 汇编中字符串还是单个字符用"或者'围起来都一样
      ; db "Welcome to masm!" , '$'
data ends

code segment
start:        mov ah , 2      ; 设置光标位置
        mov bh , 0
        mov dh , 12
        mov dl , 32
        int 10h

        mov ax , data
        mov ds , ax
        mov dx , 0                   ; 设置待显示字符串位置,这个中断中要用dx来存放偏移
        mov ah , 9           ; 功能号9显示字符串
        ; mov bl , 11001010b     ;21h中不能设置颜色了都
        int 21h

        mov ax , 4c00h      ; 调用4ch号功能,返回值0
        int 21h  
code ends
end start

如果要显示的字符串较长,它会自动转到下一行开头处继续显示,如果到达显示也最后一行,它还能自动上卷一行。





posted on 2017-11-30 19:47  正在加载……  阅读(1305)  评论(0编辑  收藏  举报