如何在MINIX汇编代码(x86)中复制全局描述符表

时间:2018-02-06 04:28:18

标签: assembly x86 operating-system minix

MINIX 3中的代码将启动监视器(引导程序)GDT复制到内核空间并切换它。但我很难理解代码。在代码中,_gdt是在C(gdt[GDT_SIZE])中声明的描述符表数组的地址。 结构gdt如下:

struct segdesc_s {      /* segment descriptor for protected mode */
  u16_t limit_low;
  u16_t base_low;
  u8_t base_middle;
  u8_t access;          /* |P|DL|1|X|E|R|A| */
  u8_t granularity;     /* |G|X|0|A|LIMT| */
  u8_t base_high;
};

结构的大小是8个字节。宏GDT_SELECTOR的值为8

! Copy the monitor global descriptor table to the address space of kernel and
! switch over to it.  Prot_init() can then update it with immediate effect.

     sgdt   (_gdt+GDT_SELECTOR)     ! get the monitor gdtr
     mov    esi, (_gdt+GDT_SELECTOR+2)  ! absolute address of GDT
     mov    ebx, _gdt           ! address of kernel GDT
     mov    ecx, 8*8            ! copying eight descriptors
copygdt:
eseg movb   al, (esi)
     movb   (ebx), al
     inc    esi
     inc    ebx
     loop copygdt

最混乱的一行是movb (ebx), al。请帮忙。

1 个答案:

答案 0 :(得分:3)

这是一种奇怪的asm语法。它正在使用()作为AT& T语法等内存操作数,但只有在英特尔语法的左侧目标才有意义。 (它还使用AT& T风格的助记符后缀作为操作数大小,如movb用于字节mov。)

我认为它基本上是NASM语法,但使用()代替[] ,因为评论说mov ebx, _gdt是地址的mov-immediate。在GAS .intel_syntax noprefix中,这将是MASM语法中的加载。

Minix的编译器有自己的asm风格,它是documented here(感谢@MichaelPetch)。

所以这是一个一次一个字节的复制循环,从es:esids:edi,用于ecx=8*8个字节。这正是评论说它确实如此,这样可以很容易地找出我之前从未见过的语法。

movb (ebx), al将AL存储到内存中,位于EBX中的地址。即NASM mov [ebx], al或AT& T mov %al, (%ebx)

商店正在使用EBX的默认段选择器,即DS。您通常不需要在32位模式下提及段,但请注意加载上的eseg前缀。您尚未展示,评论未提及,ES设置的内容,以及与DS不同的原因/方式。

代码似乎针对代码大小进行了优化,而不是速度(这很好,因为它只在启动时运行一次)。例如它使用慢loop指令,并且一次复制一个字节,因此它可以inc指针(1个字节)而不是add esi, 4(3个字节)。尽管如此,我怀疑使用索引寻址模式,你可以使它只是一样小,但一次复制4个字节。 (字节数固定为8*8,因此它总是4的倍数。)

循环非常接近rep movsb (or rep movsd)所做的,即将ecx元素从DS:(E)SI复制到ES:(E)DI。 (可以使用细分前缀覆盖ds,因此您可以例如从fs:esi复制到es:edi)。但是在Minix代码中,加载来自ES:某些内容,而movs始终使用es作为目标细分。

fseg rep movsd会比循环更紧凑(也更快),但可能会有适当设置段寄存器的障碍。使用EDI和ESI代替ESI和EBX不应成为障碍。