【问题标题】:How to change data segment? What am I doing wrong?如何更改数据段?我究竟做错了什么?
【发布时间】:2013-01-14 06:37:39
【问题描述】:

我正在开发一个 32 位操作系统,并且开发了一个可以正常工作的 ELF 加载程序。现在我没有启用分页(我计划稍后,但现在我只是试图加载内核模块)并且我试图在启动时执行模块。基本上因为此时多任务处理还没有完全实现,我只想加载每个模块,调用 init(它将安装中断处理程序并设置模块的用途)然后退出并执行下一个。它可以工作,但我不能用 C 程序中的指针做任何事情(因为它仍然认为它正在使用内核数据段)。所以基本上我想做的是创建一个新的数据段,指向 RAM 中的模块 .data 段。我通过在 GDT 中设置条目号 6 来做到这一点。

setGDTEntry(6, DataAddress,DataSize, 0xF2, 0xCF);

setEntry 方法工作得很好,看起来像

void setGDTEntry(int num, uint Base, uint limit, byte access, byte gran)

同样,两者都 100% 工作,当我更改数据段选择器时会出现我遇到的问题。我在汇编中这样做,ELFs 入口点存储在 EAX 中。

mov ax, 30h ; This is 8 * 6, the GDT entry containing the new data segment
mov ds, ax ; set data segment
call address ; JUMP!!!!
mov ax, 0x10 ; Restore kernel data segment
mov ds, ax ; set data segment

这将导致我的内核崩溃,给出 CPU 异常 0x6,无效操作码。我的 C 程序的源代码只是一个将文本复制到视频 RAM 的 hello world 程序(没什么可看的。)。有谁知道我做错了什么?我对 GDT 和段选择器的整个概念很陌生............而且我现在不能启用分页或多任务,我真的不想解释为什么......

【问题讨论】:

    标签: assembly data-segment


    【解决方案1】:

    首先,你不仅要设置ds,还要设置esss。如果你不这样做,一些指令将使用ds.base 作为段基(例如mov eax, [ebx]),而其他指令将使用ss.base(例如mov eax, [ebp+8])或es.base(例如rep movsd),它们将会导致地址不一致。

    您可能遇到的另一个问题是错误的cs(无效指令异常表明了这一点)。 x86 代码通常不是位置独立的。就像您必须创建并使用单独的数据段来补偿数据段在内存中加载位置和它们应该在内存中的位置之间的差异(各种 ELF 标头/段告诉您),您必须对代码部分执行相同的操作。您可以使用远调用、远跳转或远返回来更改cs

    【讨论】:

      猜你喜欢
      • 2013-08-06
      • 1970-01-01
      • 2016-07-18
      • 2019-12-23
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      相关资源
      最近更新 更多