0

我正在开发一个 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% 工作,当我更改数据段选择器时会出现我遇到的问题。我在汇编中执行此操作,ELF 入口点存储在 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 和段选择器的整个概念很陌生............而且我现在不能启用分页或多任务处理,我真的不想解释为什么......

4

1 回答 1

0

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

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

于 2013-01-15T09:56:40.730 回答