x86中的中断描述符表

时间:2015-02-07 13:05:19

标签: assembly x86 boot

我正在尝试为x86实现一个boot-loader。初始版本只使用BIOS中断调用在屏幕上打印“Hello”。我正在使用QEmu和GDB按顺序浏览我的代码。 以下是代码片段:

mov ah, 0x0e
mov al, 'H'
int 0x10
mov al, 'e'

boot-loader从地址0x07c00开始。 根据我的理解,BIOS设置中断描述符表从地址0x0到0x3ff(1024字节)。 IDT有256个32位条目,每个条目指定16位段和16位偏移量,它是中断服务程序的地址。 因此,当我执行:

int 0x10

我应该跳到IDT第17条所指的地址。当我检查内存0x10的内容时,它包含以下数据“0xf000ff53”,因此程序应跳转到0xfff53位置,但我发现它在执行

后跳转到0xc4c71
int 0x10

指令 为什么会发生这种情况?

1 个答案:

答案 0 :(得分:3)

  

当我检查内存0x10的内容时

有你的问题。由于每个向量是4个字节,因此中断0x10的条目位于地址0x40

(gdb) x/a 0x40
0x40:   0xc0004d65
(gdb) p/x $cs
$4 = 0xc000
(gdb) p/x $eip
$5 = 0x4d66

我的qemu + gdb组合似乎在中断后跳过一个字节,这可能是一个错误。

  

但我们确定跳过一个字节是一个错误

是。我们来测试一下:

xor ax, ax
mov ds, ax
mov ax, [0x40]
mov dx, [0x42]
mov [old], ax
mov [old+2], dx
mov word [0x40], handler
mov [0x42], cs
mov ah, 0x0e
mov al, 'H'
int 0x10
jmp $
handler:
inc ax
jmp far [old]
old: dd 0

这会将int 0x10挂钩到我们的handler,使用单字节指令(操作码ax)递增0x40,然后转到原始处理程序。如果你运行它,你会看到它打印I而不是H,所以inc ax正确执行。此外,您可以在处理程序上放置一个断点并看到它停在那里,然后继续执行原始处理程序:

Breakpoint 2, 0x00007c24 in ?? ()
(gdb) x/a 0x7c29
0x7c29: 0xc0004d65
(gdb) si
0x00007c25 in ?? ()
(gdb)
0x00004d65 in ?? ()

请注意,如果您单步执行,gdb将再次跳过第一条指令:

0x00007c20 in ?? ()
(gdb) x/4i $eip
=> 0x7c20:      int    $0x10
   0x7c22:      jmp    0x7c22
   0x7c24:      inc    %ax
   0x7c25:      ljmp   *0x7c29
(gdb) p/x $ax
$4 = 0xe48
(gdb) si
0x00007c25 in ?? ()
(gdb) p/x $ax
$5 = 0xe49

您可以看到它已转到0x7c25而不是0x7c24,但ax已增加,因此inc ax已执行。

inc ax(3字节)指令替换add ax, 1的工作方式相同,因此gdb实际上是跳过第一条指令而不是一个字节。