Gcc 为什么内联汇编代码会导致三重错误?

Gcc 为什么内联汇编代码会导致三重错误?,gcc,x86,inline-assembly,osdev,gdt,Gcc,X86,Inline Assembly,Osdev,Gdt,我使用GCC和-masm=intel选项编译代码。我的内核是由GRUB这样的多引导加载程序加载的 我想加载GDT的地址,然后重新加载所有段寄存器,但这会导致三重故障(虚拟机重新启动)。如果我在本机程序集中(在.asm文件中)使用该代码,则该代码可以工作 gdt.c: #包括“gdt.h” GDT-gdtp; uint64_t gdt[gdt_条目]; 无效集合项(整数x、无符号整数基、无符号整数限制、整数标志){ gdt[x]=限制&0xFFFFL; gdt[x]|=(base&0xffffff

我使用GCC和
-masm=intel
选项编译代码。我的内核是由GRUB这样的多引导加载程序加载的

我想加载GDT的地址,然后重新加载所有段寄存器,但这会导致三重故障(虚拟机重新启动)。如果我在本机程序集中(在.asm文件中)使用该代码,则该代码可以工作

gdt.c:

#包括“gdt.h”
GDT-gdtp;
uint64_t gdt[gdt_条目];
无效集合项(整数x、无符号整数基、无符号整数限制、整数标志){
gdt[x]=限制&0xFFFFL;

gdt[x]|=(base&0xffffffLL>4)&0xffLL>16)&0xfLL)24)&0xffLL)问题不在内联汇编代码中,但是我在您添加到问题中的代码片段中看到了一些错误:

  • GDT\u标志
    条目:

    GDT_SIZE = 0x3
    
    应该是:

    GDT_SIZE = 0x4
    
  • 您正在使用多引导加载程序,并且将访问0x100000以上的内存。您的GDT条目没有设置
    GDT\u粒度
    位,因此您被限制为较低的1MB内存。此外,您还没有用
    GDT\u读写
    位标记任何描述符。GDT初始化应为:

    void gdt_init() {
        gdtp.limit = GDT_ENTRIES * 8 - 1;
        gdtp.pointer = gdt;
    
        set_gdt_entry(0, 0, 0, 0);
        set_gdt_entry(1, 0, 0xFFFFFFFF, GDT_GRANULARITY | GDT_READ_WRITE \
                      | GDT_SIZE | GDT_EXECUTABLE | GDT_SEGMENT | GDT_PRESENT);
        set_gdt_entry(2, 0, 0xFFFFFFFF, GDT_GRANULARITY | GDT_READ_WRITE \
                      | GDT_SIZE | GDT_SEGMENT | GDT_PRESENT);
        set_gdt_entry(3, 0, 0xFFFFFFFF, GDT_GRANULARITY | GDT_READ_WRITE \
                      | GDT_SIZE | GDT_EXECUTABLE | GDT_SEGMENT | GDT_PRESENT | GDT_RING3);
        set_gdt_entry(4, 0, 0xFFFFFFFF, GDT_GRANULARITY | GDT_READ_WRITE \
                      | GDT_SIZE | GDT_SEGMENT | GDT_PRESENT | GDT_RING3);
    
        asm volatile(
            "lgdt %0\n"
            "mov eax, 0x10\n"
            "mov ss, eax\n"
            "mov es, eax\n"
            "mov ds, eax\n"
            "mov gs, eax\n"
            "mov fs, eax\n"
            "jmp 0x08:1f\n"
            "1:\n"
            : : "m" (gdtp) : "eax"
        );
    }
    

建议
  • 在操作系统开发的早期调试GDT代码和中断时,我发现使用BOCHS emulator很有用。当出现问题(即三重故障)时,它将转储处理器状态信息,并具有将这些表转储到控制台的
    info gdt
    info idt
    命令。要使用BOCHS进行操作系统开发,您可以生成ISO映像并作为CD-ROM引导

  • 您正确地编码了
    set\u gdt\u条目
    ,只使用较低的20位,而丢弃较高的12位。为了使内容更具可读性,我建议使用0x00000和0xFFFFF(包括)之间的值指定限制。当使用
    GDT_粒度
    时,CPU将限制值左移12位,并将较低的12位设置为0xFFF。当设置
    GDT_粒度
    时,限制将被视为4KB页面,而不是字节

    当未设置
    GDT\u粒度时,限制值仅为0x00000和0xFFFFF之间的20位值,将限制指定为字节,而不是4KB页面


它是一个包含限制和GDT数组指针的结构。问题是,如果我将程序集放在boot.asm中,它会工作,我会编辑我的问题并显示它。我编辑了我的问题,但它仍然有三个错误。谢谢。我没有注意到我混淆了它是由GRUB加载的,我认为GRUB在1MiBI更改了它,但它仍然存在三重错误必须设置粒度和读写。它现在可以工作了。谢谢。我已经安装了bochs,但我不知道它有像info idt和info gdtDo这样的命令。我必须将限制更改为0xFFFFF,因为粒度已设置?@Grevak,不,你不必,但你可以进行更改(使代码更具可读性)-您的编码方式只影响最下面的20位,而最上面的12位会被丢弃。我还有一个问题:为什么必须设置粒度位?如果不设置,处理器会将限制解释为字节。粒度是在32位保护模式下强制的吗?此时文档似乎很混乱