x86保护模式下段寄存器的用途是什么?

Kra*_*rab 11 x86 assembly cpu-registers memory-segmentation

我需要修改一些DLL,但我不知道,什么excatly确实段寄存器(DS,SS,...)的保护模式.我在学校里学到了真正的16位模式,其中段寄存器在正常寄存器中乘以16加偏移量,在物理存储器中提供有效地址.在保护模式下,有一些平面内存模型和虚拟内存,每个进程"有"4GB内存,所以如果寄存器有32位,那么我只能通过"偏移"寄存器来寻址虚拟内存的每个字节.例如,哪些瞳孔具有保护模式中的段寄存器

mov eax, dword ptr ds:[20037DA0] 
Run Code Online (Sandbox Code Playgroud)

Pyj*_*ong 7

基本上,目的与实际模式相同,只是它们的工作方式略有不同.您的示例中的DS在您的GDT中选择一个内存描述符(谷歌这个术语,如果你真的想理解这一点,"全局描述符表"),它包含基地址,结束地址,粒度等信息.然后你的偏移量被添加到基地址, 结束.如果你在windows上(我在linux上打赌它一样),你根本不必担心这些段寄存器,正如你所说的扁平模型,这意味着所有内存应该只有一个描述符,所以如果你不改变这些寄存器应该像它们甚至不存在一样工作.

  • @nrz虽然`ds/es.base`肯定不同于`ss.base`(这是你无法互换使用这些段的最基本原因),但这在32位保护中是非常罕见的设置模式并且可能需要额外的指令来传递C/C++中的局部变量地址(您需要考虑段基差,因此可以通过被调用函数中的`ds`访问本地,就像全局变量一样) . (3认同)

Mar*_*nau 7

一些历史背景

8086始终使用每段固定的64KiB窗口,其起始地址由(段寄存器*16)计算.由于80286在内存中有一些特殊的表(GDT和LDT).这些表包含段的起始地址,长度和访问权限.段寄存器(CS,DS,ES,SS - 以及80386:FS,GS)包含这些表的索引.

因此理论上,操作系统可以以它想要的方式设置段的偏移量和长度:在8086 DS = 0x0123意味着:段是从地址0x01230开始的64KiB.在32位模式下,DS = 0x0123可能意味着:段从地址0xABCD开始,长度为0xEF字节 - 这取决于操作系统创建的GDT和LDT表的内容.尝试访问此范围之外的段(如果长度<0x1000,则DS:0x1000)将导致异常(中断).

现在的情况

但是,大多数现代32位操作系统不再使用段寄存器.由于访问权限问题,它们的值是根据模式(内核或用户)设置的.起始地址通常为0,长度为4GiB.

使用MMU完成实际内存保护,以便在用户模式下无法访问某些内存区域.在现代操作系统中,MMU绝对是必不可少的.它将"绝对"虚拟地址映射到检查访问权限违规的真实物理地址.

有一个例外:某些操作系统(例如Windows和Linux)使用FS和/或GS段来指向不同的内存区域.

因此,在64位模式下,x86处理器仅将CS寄存器用于访问权限问题,FS和GS可用于向每个地址添加偏移量.据我所知DS,ES和SS不使用,而寄存器FS和GS的内容无关紧要,但有一些特殊的寄存器明确地将偏移量添加到使用FS或GS的操作中.