汇编语言(王爽第三版)检测点15
检测点 15.1
(1)仔细分析一下上面的int 9中断例程,看看是否可以精简一下?
其实在我们的int 9中断例程中,模拟int指令调用原int 9中断例程的程序段是可以精简的,因为在进入中断例程后,IF和TF都已经置零,没有必要再进行设置了。对于程序段:
pushf ;将寄存器值入栈
pushf ;将寄存器值入栈
pop ax ;弹栈到ax中,(ax)=(flag)
and ah, 11111100b ;注意是高8位,IF和TF是标志位中的第9和第8位,按位与
push ax ;将修改后的值入栈。
popf ;将修改后的值弹栈到标准寄存器中。这时IF=0,TF=0
call word ptr ds:[0];调用原来的int9中断例程。
可以精简为:
pushf
call word ptr ds:[0]
两条指令。
程序分析:
【1】由于我们无论是调用那个中断处理例程,CPU都干如下的活:
(1)从中断信息中取得中断类型码
(2)标志寄存器入栈保存(因为在中断过程中要改变标志寄存器的值。)
(3)设置标志寄存器的第8位TF(跟踪标志)和第9位IF(中断标志)为0.(防止单步中断和其他外部中断发生)
(4)cs的内容入栈
(5)IP的内容入栈
(6)设置ip的值为:N(中断类型码)*4;设置cs的值:N*4+2
所以第二个pushf是多余的指令,然后是设置IF和TF的指令也是多余的了。
【2】为什么还有个pushf呢,这个pushf指令压栈标志寄存器,确实是保护标志寄存器的值,也是为了与中断程序中的iret(它内部CPU操作步骤有popf)相呼应。如果没有这个pushf,那么iret指令执行中出栈到标准寄存器的值可能不正确了。
(2)仔细分析上面程序中的主程序,看看有什么潜在的问题?
在主程序中,如果在执行设置int 9中断例程的段地址和偏移地址的指令之间,发生了键盘中断,则CPU将转去一个错误的地址执行,将发生错误。
找出这样的程序段,改写它们,排除潜在的问题。
提示:注意sti和cli指令的用法。
程序分析:
【1】关于设置中断向量表的指令,在程序中就2段。
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs ;将新的int9入口地址写入中断向量表中
---
; 将中断向量回写回中断向量表中
mov ax, 0
mov es, ax ;将es指向0000段内存中断向量表
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
如果在指令执行在这2段中间,引发了键盘中断事件,由于正在设置中断向量表,故(ip)和(cs)值可能不确定。为了避免这2段代码不受到中断事件的干扰,将中断屏蔽了。
【2】sti和cli指令的用法:
cli 禁止中断发生
sti 允许中断发生
【3】这二段代码前后加上cli和sti指令即可:
;在中断向量表中设置新的中断入口地址的时候不让其发生中断
cli
mov word ptr es:[9*4],offset int9
mov word ptr es:[9*4+2],cs
sti
恢复中断向量表int9的源地址时:
cli
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
sti