assembly - 在 ds 中移动 0x18 后,QEMU 寄存器和 eip 被破坏

标签 assembly x86 qemu bootloader protected-mode

我目前正在学习构建自己的引导加载程序。我能够设置 gdt 并进入保护模式。但是当我尝试将 0x18(gdt 中的第三段)移动到 ds 时,我的大部分寄存器都被破坏了,eip 得到了随机的东西

导致错误的代码:(我已经处于 protected 32 位模式)

mov eax, 0x18
mov ds, eax  <--- After this instruction registers are destroyed
mov eax, [0x0000]

我的 gdt 条目:

; GDT null segment                                                                                   
  8 gdt_null:
  9     dq 0
 10 
 11 ; GDT code segment (4GB)
 12 gdt_code:
 13     dw 0xFFFF
 14     dw 0x00
 15     db 0x00
 16     db 10011010b
 17     db 11001111b
 18     db 0x00
 19 
 20 ; GDT data segment (4GB)
 21 gdt_data:
 22     dw 0xFFFF
 23     dw 0x00
 24     db 0x00
 25     db 10010010b
 26     db 11001111b
 27     db 0x00
 28 
 29 ; GDT video segment
 30 gdt_video:
 31     dw 0xFFFF
 32     dw 0x00
 33     dw 0x00
 34     dw 10010010b
 35     db 11001111b
 36     db 0x00

指令前的gdb:

─── Output/messages ─────────────────────────────────────────────────────────────────────────────────────
─── Assembly ────────────────────────────────────────────────────────────────────────────────────────────
0x00007cf4 ? mov    ds,eax
0x00007cf6 ? mov    eax,ds:0x0
0x00007cfb ? hlt    
0x00007cfc ? or     BYTE PTR [eax+0x65],0x6c
0x00007d00 ? ins    BYTE PTR es:[edi],dx
0x00007d01 ? outs   dx,DWORD PTR ds:[esi]
0x00007d02 ? and    BYTE PTR [edi+0x6f],dl
─── Expressions ─────────────────────────────────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────────────────────────────────
   eax 0x00000018       ecx 0x00000002       edx 0x00000080       ebx 0x00000000       esp 0x00002000   
   ebp 0x00000000       esi 0x00000000       edi 0x00000000       eip 0x00007cf4    eflags [ PF ]       
    cs 0x00000008        ss 0x000007e0        ds 0x00000010        es 0x000009e0        fs 0x00000000   

指令后的 gdb:

─── Output/messages ─────────────────────────────────────────────────────────────────────────────────────
─── Assembly ────────────────────────────────────────────────────────────────────────────────────────────
0x0000e05b ? add    BYTE PTR [eax],al
0x0000e05d ? add    BYTE PTR [eax],al
0x0000e05f ? add    BYTE PTR [eax],al
0x0000e061 ? add    BYTE PTR [eax],al
0x0000e063 ? add    BYTE PTR [eax],al
0x0000e065 ? add    BYTE PTR [eax],al
0x0000e067 ? add    BYTE PTR [eax],al
─── Expressions ─────────────────────────────────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────────────────────────────────
   eax 0x00000000       ecx 0x00000000       edx 0x00000663       ebx 0x00000000       esp 0x00000000   
   ebp 0x00000000       esi 0x00000000       edi 0x00000000       eip 0x0000e05b    eflags [ ]          
    cs 0x0000f000        ss 0x00000000        ds 0x00000000        es 0x00000000        fs 0x00000000   
    gs 0x00000000   

正如您所看到的,大多数寄存器都被破坏了,eip 应该在其他地方,并且该位置没有真正的代码。在我在 ds 中移动 0x10 之前有一些指令,它可以正常工作,没有任何问题。这是qemu的bug吗?我不想在我的真实电脑上尝试这个,因为谁知道会发生什么?大家有什么想法吗?

最佳答案

寄存器被废弃的原因是您的系统发生三次故障并返回实模式。 CS:IP 之后是 0xf000:e05b,它位于 BIOS ROM 中。 GDB 无法正确处理实模式,并且在 0x0000:0xe05b 处显示指令,因为它不知道段寄存器 0x​​f000 也构成了地址的一部分,并从错误的内存位置反汇编了指令。那段内存似乎被零填满了。在操作系统开发的早期调试此类问题时,BOCHS 是一个更好的调试器。 BOCHs 有一个 info gdt 命令,可以显示当前加载的 GDT。如果某个条目已损坏,您会更容易看到它。

看来您已成功设置CS选择器寄存器(在三重故障之前),我假设您的部分GDT是有效的。我的第一个观察结果是 GDT 中的 gdt_video 描述符的布局不正确。你有:

; GDT video segment
gdt_video:
    dw 0xFFFF
    dw 0x00
    dw 0x00             ; <------ This needs to be a byte
    dw 10010010b        ; <------ This needs to be a byte
    db 11001111b
    db 0x00

应该是:

; GDT video segment
gdt_video:
    dw 0xFFFF
    dw 0x00
    db 0x00
    db 10010010b
    db 11001111b
    db 0x00

您可能还有其他问题,但根据给定的信息,这是我观察到的唯一不正确的地方。


其他观察结果

  • 尚不清楚您为何创建 gdt_video 描述符。您已将其设为平面 4GB 数据描述符,就像 gdt_data 描述符一样。您在此处显示的两个描述符是相同的。您可以使用 0x10 加载 DS 选择器。
  • 您没有显示所有代码,但我注意到在三重错误之前调试器说:

    ss 0x000007e0        ds 0x00000010        es 0x000009e0        fs 0x00000000
    

    我希望您打算设置SS(和ESP)、ESFS和< em>GS 在某个时刻。 SS:ESP 应在使用与堆栈交互的任何指令之前设置(即:pushpopcallret等)

关于assembly - 在 ds 中移动 0x18 后,QEMU 寄存器和 eip 被破坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55957711/

相关文章:

c - qemu arm ubuntu 磁盘镜像中出现段错误?

assembly - 从汇编中的字符串中提取子字符串

x86 - 使用字节分隔符快速 SIMD 提取可变大小字段

x86 - 不同的进程可以同时运行RDTSC吗?

error-handling - 系统编程qemu : unknown keycodes `(unnamed)'

c - 在 STM32F1 上的应用程序之间跳转

assembly - 如何为 Risc-V(汇编语言)编写 NOT 操作?

assembly - MIPS:lw(加载字)指令

c++ - 将 C++ 转换为 MIPS 程序集

performance - 为什么 SSE 指令保留 YMM 寄存器的高 128 位?