除了条件转移指令之外,还有几个指令在执行时也要判断条件,比如刚刚讨论过的LOOPZ/LOOPNZ,以及前面学习过的指令前缀REPZ/REPNZ等。其实,中断指令也有一条是需要判断条件的,当然,我们前面学习过的指令INT并没有这样的要求,这是一条新的指令:
助记符:INTO(Interrupt if Overflow)
用 途:如果发生溢出则执行中断
格 式:INTO
执 行:执行INTO指令时,CPU首先判断OF标志位,如果OF=1,则CPU自动
执行4号中断服务程序;如果OF=0,则CPU继续执行下面的程序如果不考虑此指令判断的条件,则可以用"INT 04"代替这条指令。这条指令很不常用,不过在一些加密软件中有时会常见它的身影。需要提到的是这条指令产生的中断也是处理机中断。实际上处理机中断有些也是需要指令才能产生的,这一点与前面我们讨论过的除法错中断、单步中断不同。除法错、单步中断是在CPU执行指令时自动产生,而溢出中断则不同,如果CPU没有执行INTO指令,即使运算发生溢出它也不会自动转去执行4号中断服务程序。
还有一条中断指令也很特殊,这条指令就是"INT 3"。从形式上看这条指令与"INT 10H"、"INT 21H"没有什么区别,但是它编译之后的机器码却与一般的INT指令有很大的不同。那么不同之处在哪里?这个问题咱们可以请教DEBUG:
C:\ASM\>DEBUG[Enter] -a[Enter] 0F6A:0100 mov ax,0e07 0F6A:0103 int 10 0F6A:0105 int 3 0F6A:0106 [Enter] -u100 105 [Enter] 0F6A:0100 B8070E MOV AX,0E07 0F6A:0103 CD10 INT 10 0F6A:0105 CC INT 3
从反汇编的的结果可以看出"INT 3"与一般的INT指令的区别:指令"INT 10"编译成的机器码是"CD 10",很明显,"10"就是中断号,"CD"是INT指令的机器码。照此来看"INT 3"应该编译成"CD 03"才对,然而反汇编的结果显示出"INT 3"的机器码只有一个字节--0CCH。所以说"INT 03"实际是一条单字节中断指令,尽管形式上它与"INT 10"之类的指令一致。
这条指令有什么作用呢?我们不妨把这个程序运行一下,看看会有什么结果产生。
-g=100[Enter] AX=0E07 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0F6A ES=0F6A SS=0F6A CS=0F6A IP=0105 NV UP EI PL NZ NA PO NC 0F6A:0105 CC INT 3
除了喇叭里发出一声鸣叫之外,屏幕上居然显示出了所有寄存器的内容。我们既没有用R命令观察寄存器,也没有用T、P命令跟踪这个程序的执行,屏幕上所显示的这些东西又是从何而来呢?
问题的答案是很有戏剧性的:我们在0105处打了一个断点。
3号中断其实是专为DEBUG提供的,DEBUG内部包含有3号中断的服务程序,启动DEBUG之后它会修改中断向量表,使3号中断向量指向DEBUG内部的服务程序。这段服务程序的作用就是将所有寄存器的内容显示在屏幕上并等待命令。所谓设置断点,实际过程就是DEBUG将断点地址处的一个字节取出存入它自己的数据区内,然后在断点地址处填入0CCH。这样当程序执行到断点地址处就会产生3号中断,于是我们就能观察到各个寄存器的内容。在上面的实验程序中,我们人为地在0105处输入了指令INT 3,作用等同于打上一个断点。
这样来看有关DEBUG程序的"T"命令与"G"命令的详细情况我们已略知一二,"T"命令主要依靠单步中断,可以通过设置标志寄存器的TF位实现;而"G"命令设置断点主要依靠单字节中断指令"INT 3"。必须注意,"P"命令虽然功能与"T"命令相似,但是"P"命令也是依靠"INT 3"实现,它不依靠单步中断。