如何更改数据段?我究竟做错了什么?

时间:2013-01-14 06:37:39

标签: assembly data-segment

我正在开发一个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程序的源代码只是一个hello world程序,它将文本复制到视频RAM中(没什么可看的。)。有谁知道我做错了什么?我是GDT和分段选择器的整个概念的新手..........我现在不能启用分页或多任务处理,我真的不想解释为什么......

1 个答案:

答案 0 :(得分:0)

首先,您不仅需要设置ds,还需要设置esss。如果不这样做,某些说明将使用ds.base作为细分基础(例如mov eax, [ebx]),而其他说明将使用ss.base(例如mov eax, [ebp+8])或{{1} (例如es.base)并且它们会有所不同,从而导致寻址不一致。

您可能遇到的另一个问题是错误的rep movsd(无效的指令异常表明了这一点)。 x86代码通常不是位置独立的。就像你必须创建和使用一个单独的数据段来弥补数据部分在内存中加载的位置和应该在内存中的位置之间的差异(各种ELF标题/部分告诉你),你必须为代码部分做同样的事情。您可以使用远程呼叫或远程跳转或远程返回来更改cs