实验13-1 编写、应用中断例程-显示字符串
1) 思路:
- 看到题目的第一眼,总感觉题目很熟悉,好像之前写过,仔细想想,原来是 实验10-1 写过一个 显示字符串的子程序
- 通过第 13 章的学习,我们知道 int 指令 和 iret 指令 的配合使用与 call 指令 和 ret 指令 的配合使用具有相似的思路,因此我们可以将 实验10-1 的程序做个简单的修改就可以了
- 对于除法错误处理的中断例程最后的指令为
mov ax, 4c00h
int 21h
因为这个是除法溢出错误,所以中断例程执行结束后不需要返回到调用程序中,因此可以直接返回到 DOS- 对于非错误的中断例程(特指 功能性的中断例程),要 int 指令 和 iret 指令 的配合使用
2) int 7ch 中断例程代码:
文件名:exp131.asm
assume cs:code
code segment
start:
mov ax, cs
mov ds, ax
mov si, offset show_str ; 设置 ds:si 指向源地址
mov ax, 0
mov es, ax
mov di, 200h ; 设置 es:di 指向目的地址
mov cx, offset show_str_end - offset show_str ; 设置 cx 为传输长度
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
show_str:
push ax
push cx
push dx
push si
push di
push es ; 将子程序中使用的寄存器入栈
mov ax, 0b800h ; 显存的起始地址
mov es, ax
mov di, 0
mov al, 160
mul dh
add di, ax ; 计算显示的位置
mov ax, 2
mul dl
add di, ax ; 计算显示的位置
mov al, cl ; 字符的属性值
change:
mov ch, 0
mov cl, ds:[si]
jcxz ok ; 条件转移,如果 cx 为 0 则跳转
mov es:[di], cl
mov es:[di + 1], al
inc si
add di, 2
jmp short change
ok:
pop es
pop di
pop si
pop dx
pop cx
pop ax ; 将子程序中使用的寄存器出栈
iret
show_str_end:
nop
code ends
end start
3) 跟踪程序代码:
文件名:exp131d.asm
assume cs:code
data segment
db "welcome to masm! ", 0
data ends
code segment
start:
mov dh, 10 ; 行号
mov dl, 10 ; 列号
mov cl, 2 ; 颜色
mov ax, data
mov ds, ax
mov si, 0 ; ds:si 指向字符串首地址
int 7ch
mov ax, 4c00h
int 21h
code ends
end start
4) 程序运行效果:
程序运行效果
5) Debug 跟踪调试过程:
CPU 执行 int n 指令,相当于引发一个 n 号中断的中断过程,执行过程如下:
- 取中断类型码 n
- 标志寄存器入栈,IF=0,TF=0
- CS、IP 入栈
- (IP)=(n * 4),(CS)=(n * 4 + 2)
iret 指令的功能相当于:
pop IP
pop CS
popf
原理:
CPU 执行 int 7ch 指令进入中断例程之前,标志寄存器、当前的 CS 和 IP 被压入栈中,在执行完中断例程后,使用 iret 指令,将恢复 int 7ch 执行前的标志寄存器和 CS、IP 的值,从而接着执行应用程序。
Debug 跟踪调试过程