You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

加载GDT时操作系统触发三重故障的技术求助

加载GDT时触发三重故障的排查

加载GDT(全局描述符表)时触发三重故障,参考过OSDEV的GDT相关文档。

怀疑有问题的汇编代码

global loadGDT
loadGDT:
    mov ax, [esp + 4]
    mov [gdtr], ax
    mov eax, [esp + 8]
    mov [gdtr + 2], eax
    lgdt [gdtr]
    ret

global reloadSegments
reloadSegments:
    jmp 0x00:.reload_cs
.reload_cs:
   mov   ax, 0x00
   mov   ds, ax
   mov   es, ax
   mov   fs, ax
   mov   gs, ax
   mov   ss, ax
   ret

段配置信息

  • 代码段:
    • 基址:0
    • 限长:0xFFFFF
    • 访问字节:10011011
    • 标志位:1000
  • 数据段:
    • 基址:0
    • 限长:0xFFFFF
    • 访问字节:10010011
    • 标志位:1000

原本使用0x08和0x10作为段选择子,因基址都是0改成0,故障依旧。

补充的C代码

#include <gdt.h>

uint64_t GDTEntryToInt(SegmentDescriptor descriptor){
    uint64_t rv = 0;
    rv = rv | ((descriptor.limit & 0xFFFF) << 0);
    rv = rv | ((descriptor.base & 0xFFFFF) << 16);
    rv = rv | ((descriptor.accessByte & 0xFF) << 40);
    rv = rv | ((descriptor.limit & 0xF0000) << 48);
    rv = rv | ((descriptor.flags & 0xF) << 52);
    rv = rv | ((descriptor.base & 0xFF0000) << 56);
}


void GDT_Load(){
    gdt[0] = 0;
    SegmentDescriptor codeDescriptor;
    codeDescriptor.base = 0;
    codeDescriptor.limit = 0xFFFFF;
    codeDescriptor.accessByte = GDT_PRESENT | GDT_RING_KERNEL | GDT_DATA_OR_CODE_SEGMENT | GDT_CODE_SEGMENT | GDT_CODE_ONLY_RING_SET | GDT_CODE_READABLE | GDT_ACCESSED;
    codeDescriptor.flags = GDT_GRANULARITY | GDT_16BIT_PROTECTED_SEGMENT;
    SegmentDescriptor dataDescriptor;
    dataDescriptor.base = 0;
    dataDescriptor.limit = 0xFFFFF;
    dataDescriptor.accessByte = GDT_PRESENT | GDT_RING_KERNEL | GDT_DATA_OR_CODE_SEGMENT | GDT_DATA_SEGMENT | GDT_DATA_GROW_UP | GDT_DATA_WRITEABLE | GDT_ACCESSED;
    dataDescriptor.flags = GDT_GRANULARITY | GDT_16BIT_PROTECTED_SEGMENT;
    gdt[1] = GDTEntryToInt(codeDescriptor);
    gdt[2] = GDTEntryToInt(codeDescriptor);
    g_GDTR.offset = (uint32_t)gdt;
    g_GDTR.size = sizeof(gdt) - 1;
    loadGDT(g_GDTR.size, g_GDTR.offset);
    reloadSegments();
}

核心问题与修复方法

  1. GDTEntryToInt函数缺失返回值
    函数最后未添加return rv;,导致生成的GDT条目是随机垃圾值,直接破坏GDT结构。修复后函数末尾加上return rv;。

  2. GDT条目初始化错误
    gdt[2] = GDTEntryToInt(codeDescriptor);错误地将数据段位置赋值为代码描述符,应改为gdt[2] = GDTEntryToInt(dataDescriptor);。

  3. 段选择子使用错误

    • reloadSegments中jmp 0x00:.reload_cs使用空描述符的选择子0x00,无法正确加载代码段,应改为代码段选择子0x08(对应GDT第1个非空条目)。
    • 后续加载数据段寄存器时,同样不能用0x00,应使用数据段选择子0x10(对应GDT第2个非空条目)。修改后的reloadSegments代码:
      global reloadSegments
      reloadSegments:
          jmp 0x08:.reload_cs
      .reload_cs:
         mov   ax, 0x10
         mov   ds, ax
         mov   es, ax
         mov   fs, ax
         mov   gs, ax
         mov   ss, ax
         ret
      
  4. 确认GDTR结构匹配
    确保gdtr的结构是低2字节为size,高4字节为基址,与汇编中mov [gdtr], ax(存size)、mov [gdtr+2], eax(存基址)的操作一致。

内容的提问来源于stack exchange,提问作者bessieTheBoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:47:06