【发布时间】:2016-02-28 15:03:33
【问题描述】:
我目前正在遵循启用 GDT 分段的指南。我正在使用 GNU Assembler 和 Bochs 进行仿真。
我知道我需要使用 GDT 描述符加载 GDT 寄存器。我已经这样做了,接下来的步骤是现在将所有具有偏移量的段寄存器加载到代码/数据段描述符的各个位置,相对于 GDT。这样做的代码如下:
reloadSegments:
; Reload CS register containing code selector:
JMP 0x08:reload_CS ; 0x08 points at the new code selector
.reload_CS:
; Reload data segment registers:
MOV AX, 0x10 ; 0x10 points at the new data selector
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
RET
然而,我无法理解如何隐式加载带有偏移量的 CS 寄存器,而不会出现明显不可避免的结果,即跳转到 CS:IP 对指向的任何内存位置——即,如果代码段描述符是位于 GDT_start+0x10,我尝试将 0x10 加载到 CS 寄存器,虚拟机跳转到 0x10:IP,我从未进入 .reload_CS 标签。
我的例程版本(at&t 语法):
_start:
// Disable interrupts
cli
// Load GDT register with location of GDT
lgdt 0x3c
// Load location of Code segment descriptor into cs
ljmp $0x2c, $reload_cs
reload_cs:
mov $0x34, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
loop:
jmp loop
P.s:我不确定为什么 ljmp $0x2c, reload_cs 不起作用 - 将 reload_cs 与 $ 加前缀可以编译,但根据我的经验,标签通常不需要这种语法...
【问题讨论】:
-
这是一个很大的跳跃,不确定哪一部分让您感到困惑?它将跳转到给定地址,同时重新加载
CS。设置GDT是您的工作,以便您跳转到正确的位置。如果段基数是0并且您处于org 0模式,那将是正确的。 PS:lgdt 0x3c非常可疑。 -
好吧,我读到
cs必须包含相对于 GDT 的代码段的偏移量,但cs也构成了指向下一条指令的指针,即cs:ip- 因此我最终跳转到0x2c:reload_cs,这不是reload_cs的位置。到目前为止我能理解的唯一解决方案是在 GDT 中设计代码段的位置以保持cs不变,这很荒谬。我觉得我缺少一些关于汇编程序的基本知识。 -
cs:ip在保护模式下使用 GDT 条目中的基地址。您只需确保在指令中添加了偏移量的基地址会将您带到正确的位置。实现这一目标的最简单方法是在实模式下使用org 0,并将描述符条目中的基地址设为零。 -
对不起,我还是没听懂。你的意思是,在我尝试
far jmp隐式更新cs以包含 GDT 偏移量之前,我需要启用保护模式?关于将代码段作为 GDT 表的第一个偏移量的建议,我不能这样做,因为根据规范要求第一个条目用零填充,据我所知,cs不能有一个零偏移。我上传了一些图片来说明我的情况:imgur.com/a/K25OQ -
编辑:你的意思是我应该从一开始就在 0x0:0x(something) 加载整个程序,并将
reload_cs之后的代码位置向下移动足够的字节以偏移cs的变化?
标签: assembly x86 gnu-assembler osdev