3.10 中断指令
在汇编语言中,中断机制是控制程序流程和处理异步事件的重要手段。有软中断指令 (INT n
)和中断返回指令 (IRET
)。
1. 软中断指令 (INT n
)
定义与格式
- 指令格式:
INT n
代码语言:javascript复制- `n`:中断类型码,取值范围为 `0` 到 `0FFH`(即 0 到 255),总共有 256 种不同的中断类型。
功能与工作原理
- 中断矢量表:
- 中断类型码
n
对应于中断矢量表中的第n
项。 - 每个中断类型码在中断矢量表中占用 4 个字节:
- 前两个字节:存放中断服务程序(Interrupt Service Routine, ISR)的入口地址偏移量(Offset)。
- 后两个字节:存放中断服务程序的段基址(Segment Address)。
- 中断类型码
- 执行过程:
- 保存标志寄存器:
INT n
指令执行时,首先将当前的标志寄存器(Flags Register,FR
)的内容压入堆栈,以保存当前的状态。
- 清除特定标志位:
- 清除中断标志位(Interrupt Flag,
IF
)和陷阱标志位(Trap Flag,TF
),以防止嵌套中断或单步调试中断。
- 清除中断标志位(Interrupt Flag,
- 保存程序断点:
- 将当前程序计数器(即下一条指令的地址)的段基址和偏移地址压入堆栈,以便中断服务程序执行完毕后能够返回。
- 跳转到中断服务程序:
- 从中断矢量表中获取与中断类型码
n
对应的 4 个字节内容:- 偏移地址(Offset):加载到指令指针寄存器(
IP
)中。 - 段基址(Segment Address):加载到代码段寄存器(
CS
)中。
- 偏移地址(Offset):加载到指令指针寄存器(
- 这样,CPU 会跳转到指定的中断服务程序执行。
- 从中断矢量表中获取与中断类型码
- 保存标志寄存器:
示例
假设我们有一个中断类型码为 0x21
(常用于DOS的中断服务),使用 INT 21H
来调用DOS功能:
MOV AH, 09H ; DOS功能号 09H:显示字符串
MOV DX, OFFSET msg ; DS:DX 指向要显示的字符串
INT 21H ; 调用DOS中断
...
msg DB 'Hello, World!$' ; DOS字符串以 '$' 结尾
解释:
- 这里,
INT 21H
调用了DOS提供的功能,通过设置AH
和DX
寄存器来指定具体的操作(显示字符串)。
再看一个例子
代码语言:javascript复制section .text
org 100h ; 设置程序起始地址(一般用于COM程序)
start:
; 假设 AX 中已经有了要计算的数值
int 7Ch ; 调用自定义的中断 7Ch,计算 AX 中的数据的平方
; 示例计算:2 * 3456^2
mov ax, 3456h ; 初始化 AX = 3456h
int 7Ch ; 计算 3456h 的平方
; 结果存储在 DX:AX 中
; 此时 DX 中存放高16位,AX 中存放低16位
add ax, ax ; 结果乘以2,更新 AX
adc dx, dx ; 结果乘以2,更新 DX
mov ax, 4C00h ; 正常结束程序
int 21h
; 中断例程 - 中断7Ch: 计算AX中数值的平方
isr_7ch:
pusha ; 保存所有通用寄存器
; 计算 AX 的平方,并将结果存入 DX:AX 中
mov dx, ax ; 将 AX 复制到 DX 中
mul dx ; AX * DX -> DX:AX,AX 中低16位,DX 中高16位
popa ; 恢复所有通用寄存器
iret ; 返回到调用程序
section .data
软中断指令 (INT n)有哪些,都能做什么?
在 x86 汇编语言中,软中断指令 INT n
用于生成一个软件中断,通过调用操作系统或BIOS提供的服务。软中断允许程序在运行时请求操作系统或BIOS执行某些功能,类似于调用系统函数。
软中断指令概述
- 语法:
INT n
n
是中断向量号,指定了中断处理程序的入口点。
常见的软中断指令及其功能
- INT 10h: 视频服务中断
- 用途: 提供视频功能,包括显示模式设置、光标控制、字符显示等。
- 功能示例:
INT 10h
使得可以设置屏幕模式、显示光标、打印字符等。AH = 0x02
: 设置光标位置。AH = 0x0E
: 显示字符。
- INT 13h: 磁盘服务中断
- 用途: 提供磁盘操作服务,如读取和写入磁盘扇区。
- 功能示例:
INT 13h
用于访问硬盘和软盘。AH = 0x02
: 读扇区。AH = 0x03
: 写扇区。
- INT 14h: 串行端口服务中断
- 用途: 提供串行端口操作服务。
- 功能示例:
INT 14h
用于串行通信。AH = 0x00
: 初始化串行端口。AH = 0x01
: 发送字符。
- INT 15h: 扩展服务中断
- 用途: 提供系统扩展服务,例如内存管理和电源管理。
- 功能示例:
INT 15h
用于获取系统内存信息和电源管理。AH = 0xE820
: 获取系统内存范围。
- INT 16h: 键盘服务中断
- 用途: 提供键盘操作服务。
- 功能示例:
INT 16h
用于键盘输入。AH = 0x00
: 获取键盘按键。AH = 0x01
: 检测键盘按键是否被按下。
- INT 21h: DOS 系统调用中断
- 用途: 提供大量的操作系统服务,如文件操作、内存分配、程序退出等。
- 功能示例:
INT 21h
提供多种 DOS 服务。AH = 0x01
: 读取字符。AH = 0x09
: 打印字符串。AH = 0x4Ch
: 退出程序。
示例代码
下面是一个使用 INT 21h
打印字符串的示例:
ORG 100h ; 设定起始地址为 100h
MOV AH, 09h ; 功能号:打印字符串
MOV DX, OFFSET MSG ; 设置字符串地址
INT 21h ; 调用 DOS 中断
MOV AH, 4Ch ; 功能号:退出程序
INT 21h ; 调用 DOS 中断
MSG DB 'Hello, World!$', 0
当然,以下是将这段汇编代码整合到一起,并进行详细解释的内容:
代码语言:javascript复制ORG 100h ; 设定起始地址为 100h
MOV AH, 09h ; 功能号:打印字符串
MOV DX, OFFSET MSG ; 设置字符串地址
INT 21h ; 调用 DOS 中断
MOV AH, 4Ch ; 功能号:退出程序
INT 21h ; 调用 DOS 中断
MSG DB 'Hello, World!$', 0
代码解释
ORG 100h
- 含义: 指定程序的起始地址为 100h。
- 作用: 在 DOS 执行的 .COM 文件中,代码通常从内存地址 100h 开始,因为前面 100h 字节的空间用于存储程序的 PSP(程序控制块)。这个伪指令告诉汇编器生成的机器代码从地址 100h 开始。
- 打印字符串部分
MOV AH, 09h ; 功能号:打印字符串
MOV DX, OFFSET MSG ; 设置字符串地址
INT 21h ; 调用 DOS 中断
代码语言:javascript复制- `MOV AH, 09h`: 将 09h 放入 AH 寄存器中。09h 是 DOS 中断 21h 的一个功能号,表示打印以 `$` 结束的字符串。
- `MOV DX, OFFSET MSG`: 将 `MSG` 标签的地址放入 DX 寄存器中。`<font style="color:#DF2A3F;">OFFSET MSG</font>` 计算 `<font style="color:#DF2A3F;">MSG</font>` 数据的<font style="color:#DF2A3F;">起始地址</font>。DX 寄存器现在包含了字符串的地址。
- `INT 21h`: 调用 DOS 中断 21h。由于 AH 寄存器中包含 09h,这次中断调用会打印 DX 寄存器中指定的字符串(即 `MSG`)。
- 退出程序部分
MOV AH, 4Ch ; 功能号:退出程序
INT 21h ; 调用 DOS 中断
代码语言:javascript复制- `MOV AH, 4Ch`: 将 4Ch 放入 AH 寄存器中。4Ch 是 DOS 中断 21h 的功能号,表示正常退出程序。
- `INT 21h`: 调用 DOS 中断 21h。由于 AH 寄存器中包含 4Ch,这次中断调用会结束程序的执行并返回到 DOS 命令行。
- 字符串数据定义
MSG DB 'Hello, World!$', 0
代码语言:javascript复制- `MSG DB 'Hello, World!$', 0`: 定义一个名为 `MSG` 的数据字节(DB),内容是字符串 `'Hello, World!'` 以 `$` 结束,`0` 作为字符串结束符。虽然 `$` 已经足够标识字符串的结束,`0` 是为了避免潜在的字符串结束问题(尤其是对其他功能)。
整体流程
- 程序开始:
- 从地址 100h 开始执行代码。
- 打印字符串:
- 设置 AH 寄存器为 09h,准备调用打印字符串的功能。
- 将字符串的地址放入 DX 寄存器。
- 调用
INT 21h
,执行打印操作,将 “Hello, World!” 显示在屏幕上。
- 退出程序:
- 设置 AH 寄存器为 4Ch,准备调用退出程序的功能。
- 调用
INT 21h
,正常退出程序,返回到 DOS 命令行。
这个程序展示了如何在 DOS 环境下使用汇编语言打印字符串并正常退出,适用于简单的 DOS .COM 文件编程。
总结
INT
** 指令**: 通过调用软件中断,程序可以请求操作系统或 BIOS 执行特定任务。INT
** 指令的功能**: 包括视频服务、磁盘操作、串行通信、键盘输入、系统服务等。
通过不同的 INT n
指令和相关功能号,汇编语言程序可以访问底层硬件或操作系统提供的功能,执行各种系统级任务。
2. 中断返回指令 (IRET
)
定义与格式
- 指令格式:
IRET
功能与工作原理
- 作用:
**<font style="color:#DF2A3F;">IRET</font>**
指令用于从中断服务程序返回到被中断的主程序,恢复中断前的执行状态。 - 执行过程:
- 恢复标志寄存器:
- 从堆栈中弹出一个字(通常是 16 位),并将其加载到标志寄存器(
FR
)中,恢复中断前的标志状态。
- 从堆栈中弹出一个字(通常是 16 位),并将其加载到标志寄存器(
- 恢复代码段和指令指针:
- 从堆栈中依次弹出两个字(各 16 位),将其加载到代码段寄存器(
CS
)和指令指针寄存器(IP
)中,恢复中断前的程序计数器。
- 从堆栈中依次弹出两个字(各 16 位),将其加载到代码段寄存器(
- 继续执行:
- 程序控制权返回到被中断的主程序,继续执行
CALL
或INT
指令之后的下一条指令。
- 程序控制权返回到被中断的主程序,继续执行
- 恢复标志寄存器:
- 重要性:
- 必须性:在中断服务程序的最后,必须使用
IRET
指令来确保程序能够正确返回到中断前的位置。如果没有IRET
,程序将无法恢复到中断前的状态,导致程序执行混乱或崩溃。
- 必须性:在中断服务程序的最后,必须使用
示例
代码语言:javascript复制; 主程序
MAIN:
; 一些主程序代码
INT 21H ; 调用DOS中断
; 中断返回后继续执行
...
; 中断服务程序(假设自定义中断)
ISR:
; 中断服务程序的代码
...
IRET ; 返回到主程序
解释:
- 当
INT
指令被执行时,CPU 跳转到对应的中断服务程序(如ISR
)。 - 中断服务程序执行完毕后,通过
IRET
指令返回到主程序的INT
指令之后的位置,继续执行主程序的后续代码。
再看一个例子
代码语言:javascript复制section .text
org 100h ; 设置程序起始地址(一般用于COM程序)
start:
; 假设 AX 中已经有了要计算的数值
int 7Ch ; 调用自定义的中断 7Ch,计算 AX 中的数据的平方
; 示例计算:2 * 3456^2
mov ax, 3456h ; 初始化 AX = 3456h
int 7Ch ; 计算 3456h 的平方
; 结果存储在 DX:AX 中
; 此时 DX 中存放高16位,AX 中存放低16位
add ax, ax ; 结果乘以2,更新 AX
adc dx, dx ; 结果乘以2,更新 DX
mov ax, 4C00h ; 正常结束程序
int 21h
; 中断例程 - 中断7Ch: 计算AX中数值的平方
isr_7ch:
pusha ; 保存所有通用寄存器
; 计算 AX 的平方,并将结果存入 DX:AX 中
mov dx, ax ; 将 AX 复制到 DX 中
mul dx ; AX * DX -> DX:AX,AX 中低16位,DX 中高16位
popa ; 恢复所有通用寄存器
iret ; 返回到调用程序
section .data
总结
- 软中断指令 (
INT n
):- 用于调用中断服务程序,处理特定的服务或事件。
- 通过中断类型码
n
来选择具体的中断服务。 - 执行
INT
指令时,CPU 会保存当前状态并跳转到对应的中断服务程序。
- 中断返回指令 (
IRET
):- 用于从中断服务程序返回到被中断的主程序。
- 恢复中断前的程序状态,确保程序能够继续正常执行。
- 必须在中断服务程序的末尾使用,以确保程序流程的正确性。
应用场景:
- 操作系统服务调用:如DOS中断
INT 21H
提供了文件操作、设备控制等功能。 - 硬件中断处理:例如键盘输入、定时器中断等,通过中断服务程序来处理异步事件。
- 软件异常处理:如断点调试、非法操作处理等。
通过正确使用 INT
和 IRET
指令,汇编程序能够有效地管理程序流程、处理事件和调用系统服务,实现复杂的功能和响应外部事件。