本期源码,欢迎star:
https://github.com/ZYKWLJ/assembly4-homework
本系列将讲解《汇编语言》一书,本节讲解**【汇编语言】13-内中断之int中断**。
| 本节速览 |
|---|
| 1.int 是指? |
| 2.int 指令格式是?什么含义? |
| 3.int和call的区别是? |
| 4.使用堆栈来完成loop循环的本质是(一句话)? |
导读:
在 上一章-【汇编语言】12-内中断+中断程序实战
中,我们说过中断分为内中断和外中断,并且详细说明了中断机制,中断处理程序等等。本节,我们来讲述另一种内中断的形式——int中断。
所谓int中断,就是由于int指令触发的中断。
一、int指令
1.定义
int指令全称为Interupt,中断之意,那显然,int指令就是中断指令。这是专门调用中断例程的指令。
2.指令格式
int n
含义为调用n号例程的中断指令。
测试:
在测试之前,已经将0号中断(除法错误)程序安装,即执行一遍 第十二章的末尾 的程序。
源码:
;验证通过int指令来执行中断程序,具体——int 0除法中断程序执行
assume cs:codesg
codesg segment
start_:
int 0;调用除法中断程序执行
codesg ends
end start_

3.int指令的作用
一句话:将特定功能的程序借用中断程序的名义存放,并使用int执行调用之。
一般情况下,系统将一些具有一定功能的子程序,以中断处理程序的方式去提供给应用程序调用。 我们在编程的时候,可以用 int 指令调用这些子程序。
当然,也可以自己编写一些中断处理程序供别人使用。以后,我们可以将中断处理程序简称为中断例程。
2.int指令和call的异同
1.同
- 都是调用程序的指令:由上可见,
int指令的最终功能和call指令相似,都是调用一段程序。
2.异
-
调用对象不同:
int指令调用的是中断处理子程序,通常是系统提供的具有特定功能的程序,如BIOS或DOS提供的中断例程。而call指令调用的是普通子程序,是用户在自己的程序中编写的实现特定功能的代码段。
-
执行机制不同:
int指令执行时,会先将标志寄存器入栈,并将IF(中断允许标志)和TF(陷阱标志)置0,然后将CS和IP入栈,最后根据中断类型码从中断向量表中获取中断处理程序的入口地址并跳转执行。call指令执行时,仅将call指令的下一条指令的地址压入栈中,然后修改IP或CS和IP的值,跳转到子程序的入口地址执行。
-
返回方式不同:
int指令对应的返回指令是iret,iret指令会从栈中恢复原来的CS、IP和标志寄存器的值,返回中断发生前的位置继续执行。call指令对应的返回指令是ret,ret指令只需从栈中弹出原来保存的地址,送入IP或CS和IP,返回主程序继续执行。
-
应用场景不同:
int指令常用于处理系统级的事件或请求,如硬件中断、软件异常等,也可用于调用系统提供的各种服务。call指令则主要用于在用户程序内部实现函数调用或子程序调用,以实现程序的模块化和代码复用。
3.对 int、iret 和栈的深入理解
1.问题
问题: 用7ch 中断例程 完成loop指令的功能。
应用举例: 在屏幕中间显示80个“!”
2.原方法loop
既然是模仿 loop ,我们就用loop的方法来写一下看看:
;编写一个普通程序,在屏幕中间打印80个绿色感叹号
assume cs:code
code segment
; 主程序部分
start:
;显存设置
mov ax, 0b800h; 设置 es 为显存段地址(B800h 是文本模式显存起始地址)
mov es, ax
mov di, 160 * 12; di = 160 * 12,计算第 12 行的起始偏移(每行 160 字节)
mov cx, 80; cx = 80,控制循环次数(写入 80 个 '!')
s:;循环控制打印字符
mov byte ptr es:[di], '!'; 向显存 es:[di] 写入字符 '!'(字节操作)
mov byte ptr es:[di+1], 02h; 向显存 es:[di] 写入字符属性,绿色
add di, 2; di += 2,指向下一个字符位置(显存中每个字符占 2 字节,低字节是字符,高字节是属性)
loop s
end_:
mov ax, 4c00h; 程序退出,调用 21h 中断的 4C00h 功能号
int 21h
code ends
end start

3.中断改写,问题分析
我们需要使用中断程序来完成loop指令的功能。loop循环无非是很多单元动作的重叠。
那么很明显的路就是,每一次中断就完成一个基本工作单元,中断cx次,那么也就完成了loop的功能。
即整体框架如下:
;编写一个普通程序,在屏幕中间打印80个绿色感叹号
assume cs:code
code segment
; 主程序部分
start:
setup_7c:
一、安装中断程序到0000:007ch,
二、;调用中断程序
int 7ch
三、;退出程序,返回dosbox
mov ax, 4c00h; 程序退出,调用 21h 中断的 4C00h 功能号
int 21h
;具体的中断程序
interrupt_7c:
中断程序的具体操作,主要是进行地址跳转以及满足cx后的退出操作
end_interrupt_7c:;中断程序大小截止标签
nop
end_:
mov ax, 4c00h; 程序退出,调用 21h 中断的 4C00h 功能号
int 21h
code ends
end start
好了,那么我们仅仅需要实现中断安装程序 ,setup_7c和具体中断程序 interrupt_7c 即可。接下来我们依次实现。
4.安装中断程序,setup_7c
首先,我们先来实现中断安装程序:
具体原理及细节请参照: 【汇编语言】12-内中断+中断程序实战 , 这里仅仅给出源码。
中断程序安装源码:
setup_7c:
; 安装中断程序覆写到0000:007ch,
mov ax, cs
mov ds, ax
mov si, offset interrupt_7c;源地址
mov ax, 0000h
mov es, ax
mov di, 0200h;目的地址
mov cx, offset end_interrupt_7c - offset interrupt_7c
cld
rep movsb
; 中断地址表装载中断程序双地址。
mov ax, 0000h
mov ds, ax
mov di, 007ch*4 ;一个表项占4字节,所以*4
; 高字存段地址,低字存偏移地址。
mov word ptr [di], 0200h;
mov word ptr [di+2], 0000;
记住中断程序就两步,cs段覆写+中断表装载。
5.中断程序,interrupt_7c
前文我们说到, loop循环无非是很多单元动作的重复。我们使用中断完成,无非就是让每一次中断就完成一个基本工作单元,中断cx次,那么也就完成了loop的功能。
interrupt_7c:
;中断程序的具体操作,主要是进行地址跳转以及满足cx后的操作
; 地址跳转
;显存设置
mov ax, 0b800h; 设置 es 为显存段地址(B800h 是文本模式显存起始地址)
mov es, ax
mov di, 160 * 12; di = 160 * 12,计算第 12 行的起始偏移(每行 160 字节)
mov cx, 80; cx = 80,控制循环次数(写入 80 个 '!')
s:
mov byte ptr es:[di], '!'; 向显存 es:[di] 写入字符 '!'(字节操作)
mov byte ptr es:[di+1], 02h; 向显存 es:[di] 写入字符属性,绿色
add di, 2; di += 2,指向下一个字符位置(显存中每个字符占 2 字节,低字节是字符,高字节是属性)
;调用中断,中断调用后,再返回s标签,一共中断cx次
dec cx
jnz s
iret
end_interrupt_7c:;中断程序大小截止标签
nop
那么截止目前,所有组件均已ok ,完整程序为:

最低0.47元/天 解锁文章
973

被折叠的 条评论
为什么被折叠?



