第11讲:中断
本周核心:理解软中断和硬中断的区别,掌握 int/iret 的执行机制,理解中断向量表的结构。
一、中断的分类
1.1 软中断(Software Interrupt)
由程序员通过 int n 指令主动触发。int 21h 指令本身在内存中占用 2 字节(机器码 CD 21)。存在于内存中的中断称为软中断。
1.2 硬中断(Hardware Interrupt)
由外部硬件事件触发,不由程序员写 int 指令,指令本身也不存在于内存中。例如:
- int 8h:定时器中断,每约 1/18 秒自动触发一次
- int 9h:键盘中断,用户按下/释放按键时自动触发
asm
mov ax, 0 ; 假设这两条指令执行了 1/18 秒
; CPU在此处接收并执行了 int 8h 指令(定时器),但 int 8h 不在代码中
mov bx, 1
again:
add ax, bx
; 用户按了某个键
; CPU在此处接收并执行了 int 9h 指令(键盘),同样 int 9h 也不在代码中
cmp ax, 100
jb again硬中断是异步的:CPU 在执行完当前指令后检查是否有硬件中断请求,有则响应后继续执行。
二、int 指令的执行过程
以 int 21h 为例,CPU 执行此指令时做以下操作:
① pushf ; 把标志寄存器 FL 压入堆栈(也可写成 push fl)
② push cs ; 把当前代码段段地址压入堆栈
③ push offset back ; 把返回偏移地址压入堆栈
④ jmp dword ptr 0:[84h] ; 跳转到中断处理程序
; int n 的目标地址总是存放在 dword ptr 0:[n*4] 处
; dword ptr 0:[n*4] 称为 int n 的中断向量完整的例子:
asm
mov ah, 2
mov dl, 'A'
int 21h ; CPU在执行int 21h指令时做以下操作:
; ① pushf
; ② push cs
; ③ push offset back
; ④ jmp dword ptr 0:[84h]
; int n的目标地址总是存放在dword ptr 0:[n*4]处,
; dword ptr 0:[n*4]称为int n的中断向量
back:
mov ah, 4Ch
mov al, 0
int 21h中断处理程序的入口地址约定
word ptr 0:[n*4] = 中断处理程序的偏移地址
word ptr 0:[n*4+2] = 中断处理程序的段地址
例如 int 21h:
word ptr 0:[84h] = offset int_21h(int 21h 处理程序的偏移地址)
word ptr 0:[86h] = seg int_21h(int 21h 处理程序的段地址)伪代码表示的中断处理程序:
asm
int_21h: ; offset int_21h 已被保存到 word ptr 0:[84h] 中
; seg int_21h 已被保存到 word ptr 0:[86h] 中
...
iret ; ★ 中断返回指令 (interrupt return)
; CPU 在执行 iret 时做以下操作:
; ① pop ip
; ② pop cs
; ③ popfint / iret 的压栈弹栈对应关系
int n 压栈: pushf → push cs → push ip → jmp far ptr 0:[n*4]
iret 弹栈: pop ip → pop cs → popf顺序恰好是完全逆序(后进先出),多了标志寄存器 FL 的保存和恢复。
三、int 与 call far 的比较
| call far ptr f | int n | |
|---|---|---|
| 压栈内容 | cs + ip | FL + cs + ip |
| 返回指令 | retf | iret |
| 目标地址来源 | 指令中的立即数 | 中断向量表 0:[n*4] |
| 会改变 IF 标志吗 | 不会 | 会(关中断) |
四、中断向量表结构
中断向量表位于内存的最低 1024 字节(0000:0000 ~ 0000:03FF):
地址 内容
0000:0000 int 0 偏移地址 (除法错误)
0000:0002 int 0 段地址
0000:0004 int 1 偏移地址 (单步调试)
0000:0006 int 1 段地址
0000:0008 int 2 偏移地址 (NMI 非屏蔽中断)
0000:000A int 2 段地址
0000:000C int 3 偏移地址 (断点)
0000:000E int 3 段地址
...
0000:0020 int 8 偏移地址 (定时器,硬中断)
0000:0022 int 8 段地址
0000:0024 int 9 偏移地址 (键盘,硬中断)
0000:0026 int 9 段地址
...
0000:0040 int 10h 偏移地址 (BIOS 视频服务)
0000:0042 int 10h 段地址
...
0000:0084 int 21h 偏移地址 (DOS 功能调用)
0000:0086 int 21h 段地址
...
0000:03FC int FFh 偏移地址
0000:03FE int FFh 段地址五、常用中断速查表
| 中断号 | 用途 | 类型 |
|---|---|---|
| int 0 | 除法错误 | CPU 自动触发 |
| int 1 | 单步调试 | 调试器用 |
| int 3 | 断点(机器码 0CCh) | 调试器用 |
| int 8 | 定时器(约 18.2 Hz) | 硬中断 |
| int 9 | 键盘输入 | 硬中断 |
| int 10h | BIOS 视频服务(切换显示模式等) | 软中断 |
| int 21h | DOS 功能调用(I/O、文件、退出等) | 软中断 |
六、本周易错点
- 混淆 int 和 call:int 多压一个 FL 标志寄存器
- 混淆 iret 和 retf:iret 多弹一个 FL
- 中断向量表地址算错:int n 的向量在
0:[n×4],低 16 位是偏移,高 16 位是段地址 - 以为代码中出现的 int 8h / int 9h 就是硬中断——硬中断不由程序员写 int 指令
- int 3 是单字节指令(0CCh),而其他 int n 都是两字节(CD n)