在8086CPU实模式下有如下内存布局:
我们看到在000-3FF的位置是放着中断向量表。
里面放的其实是4个字节的地址(地址处放着对应的中断处理函数)。我们知道在8086实模式下,是通过cs:ip来找到要执行的指令。cs是2个字节,ip是2个字节,因此是4个字节。000-3FF一共是 0x400。而一个中断向量占4个字节。因此有0x400/4=256个中断向量。 其中比较重要的有0号中断,有0x80中断,这就是Linux系统下的系统调用。在古老的8086上还没有实现linux这个系统调用。是在386上才出现的。现在我们打算用这个0x80来模拟软中断的实现。
汇编代码如下,包括注解:
[org 0x7c00] ;标识程序从0x7c00开始
mov ax,3 ;清空屏幕
int 0x10
xchg bx,bx ;下断点
mov ax,0xb800 ;实模式下文本模式的内存地址
mov es,ax
mov ax,0 ;开辟栈空间,并且将ds,ss段置为0
mov ds,ax
mov ss,ax
mov sp,0x7c00
mov word [0x80*4],print ;将我们模拟实现的中断函数写入中断向量表中,0放入cs,print放入ip
mov word [0x80*4+2],0
int 0x80
halt:
jmp halt
print: ;模拟实现的中断函数,在屏幕中输出一个点
push ax
push bx
push es
mov ax,0xb800
mov es,ax
mov bx,[vedio]
mov byte [es:bx],'.'
add word [vedio],2
pop es
pop bx
pop ax
iret
vedio:
dw 0x00
times 510 - ($-$$) db 0
db 0x55, 0xaa
执行到此处,我们的函数调用栈就完成了。
即将开始执行我们的int 0x80:
此时我们看到直接跳到了我们写的print函数中,在栈中先压入flags寄存器,cs,ip:
最后我在讲解下iret,其实他是中断返回指令。也就是中断函数执行完毕,将会把压入的cs,ip,flags弹出栈,接着执行下一条指令。