什么是中断?
中断是bios(basic input/output system)
程序内置的一套cpu
调度事件的的程序(个人理解)它需要符合各类硬件厂商的标准,比如你想从硬盘读一些数据到内存,那么你需要调用13
号中断。但是标准化的今天,这些厂商遵循了一定的规范和标准,所以能够进行各种适配。
中断程序和call
指令调用过程类似。我们甚至可以修改中断程序。
什么是中断向量表?
词听起来很高大上,实际上就是一张表格存着我的程序在内存中的哪个位置,即当我调用int 0
的时候,我从内存0:0
位置取到4
个字节,将高位给cs
,将低位给ip
,改变程序指令指针寄存器,让cpu
跳转到对应位置去执行代码。
中断的的调用过程如下
1、取中断类型码N
2、标志位寄存器入栈 pushf
3、置为中断标志位与调试标志位。TF=0,IF=0
4、push cs push ip
5、cs=N*4+2 ip=N*4
6、调用中断程序
7、iret
出栈返回
相当于执行 call dword ptr
我们先来看看中断0
,程序如下
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
int 0
MOV AH,4CH
INT 21H
CODES ENDS
END START
我们开始调试 直接g 5
我们观察cs=0770 ip=0005
在单步t 我们发现cs=F000 ip=1060
那么这两个值从哪里来呢?我们查看数据d 0:0
的位置
d 0:0
我们发现正好是f000:1060
,而0:0
位置就是内存最开始的位置
我们持续按d命令查看相关内存发现当数据到01e0
之后就没有数据。也就是这里存了一张表,这张表是以4
个字节位单位的。并且大小1d4
为止。实际上人家规定了从内存的0~3FF
为中断向量表,一共1024
个字节,但是实际只用到了468
个字节每4
个字节表示一个中断,也就是在dos
下中断向量表有117
个中断。
我们直接运行程序结果如下0
号中断代表除法错误
对应的表格我就不贴了,用到自己百度去吧
我们再来看另一段程序
栈的设置
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
dw 8 dup(0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ax,stacks
mov ss,ax
mov sp,16
push ax
MOV AH,4CH
INT 21H
CODES ENDS
END START
MOV DS,AX
mov ax,stacks
mov ss,ax
mov sp,0
MOV AH,4CH
INT 21H
CODES ENDS
END START
我们单步按t执行,我们发现 mov sp,16
这行代码被跳过了,为什么呢?因为这里面发生了中断,将TF
标志置为0
,而TF
标志表示是否允许调试为0
则不允许,所以就t指令不产生作用。
我们在看执行push ax
指令前后栈中的数据,我们发现执行前栈中数据全为0
,而执行后发现栈中多了好多数据,我们明明就push
了一个0770
为什么前面会多出那么多数据呢?
我们来看看01a6 = 0000 0001 1010 0110
在此之前我们了解下标志位对照表
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
OF DF IF TF SF ZF AF PF CF
我们在来看看对应标志位的数据
OF=NV(0) OV(1)
DF=UP(0) DN(1)
IF=EI(1) DI(0)
SF=PL(0) NG(1)
ZF=NZ(0) ZR(1)
AF=NA(0) AC(1)
PF=PO(0) PE(1)
CF=NC(0) CY(1)
我们发现和我们以上0000 0001 1010 0110
并不对应,这个是个疑惑,这里应该是push
指令里面做了什么事情该表了相关的位。
而第二个位置的值位0771
,对应cs
,第三个位置的值000d
对应ip
这个没错,栈顶指向了我们push
进去的ax
也没错。
也就是T指令产生了调试中断。
也就是执行了上面所说的几个指令pushf
push cs
push ip
。但是我们用了t
指令所以 TF=1
实际栈中的值没有错
这个我也不知道该如何验证。