以分页分段存储器的方式编程

时间:2011-11-17 20:33:01

标签: linux memory-management operating-system x86

我对分割过程有一个令人困惑的概念。在x86 linux机器中分页。如果有人澄清从开始到结束所涉及的所有步骤,将会很高兴。

x86使用分页分段内存技术进行内存管理。

任何人都可以解释从可执行的.elf格式文件从硬盘加载到主内存到它死亡的时刻发生的事情。编译时,可执行文件中有不同的部分(文本,数据,堆栈,堆,bss)。怎么加载?如何在分页分段记忆技术下设置它们。

想知道如何为加载的程序设置页面表?想知道GDT表是如何设置的。如何加载寄存器?为什么说逻辑地址(由MMU的分段单元处理的地址是48比特(16比特的段选择器+ 32比特偏移)当它是32比特的机器时。如何存储其他16比特?从ram访问的任何东西必须是32位或4字节,如何访问16位的其余部分(加载到段寄存器中)?

提前致谢。这个问题可以有很多东西。但希望澄清可执行文件的整个生命周期。如果有人回答并就此进行讨论,将会很高兴。

3 个答案:

答案 0 :(得分:2)

Unix传统上通过分页实现了保护。 286+提供分段,386+提供分页。每个人都使用分页,很少有人真正使用分段。

在x86中,每个内存操作数都有一个隐式段(因此地址实际上是16位选择器+ 32位偏移量),具体取决于所使用的寄存器。因此,如果您访问[ESP + 8]隐含段注册为SS,则如果您访问[ESI]隐含段注册为DS,则访问[EDI+4]隐含段register是ES,...您可以通过段前缀覆盖来覆盖它。

Linux,几乎每个现代x86操作系统都使用平面内存模型(或类似的东西)。在平坦的内存模型下,每个段提供对整个内存的访问,基数为0,限制为4Gb,因此您不必担心分段带来的复杂性。基本上有4个段:内核空间代码(RX),内核空间数据(RW),用户空间代码(RX),用户空间数据(RW)。

ELF文件包含一些“程序段”和“节”的标题。部分用于链接。程序段用于加载。程序段通过mmap()映射到内存中,这会设置具有适当权限的页表条目。

现在,较旧的x86 CPU的分页机制仅提供了RW访问控制(读取权限意味着执行权限),而分段提供了RWX访问控制。结束许可考虑了分段和分页(例如:RW(数据段)+ R(只读页面)= R(只读),而RX(代码段)+ R(只读页面)= RX(读取和执行))。

因此,有一些补丁通过分段提供执行预防:例如OpenWall通过缩小代码段(具有执行权限的代码段)提供了一个不可执行的堆栈,并在页面错误处理程序中为需要从高内存地址执行的任何内容进行了特殊仿真(例如:GCC trampolines,自修改代码创建在堆栈上有效地实现嵌套函数。)

答案 1 :(得分:1)

没有分页分段这样的东西,至少在官方文档中没有。有两种不同的机制在一起工作,或多或少彼此独立:

  1. 16-bit segment selector value:16/32/64-bit segment offset value形式的逻辑地址翻译为32/64-bit virtual address,即一对2个数字。
  2. virtual address翻译成32/64-bit physical address
  3. 逻辑地址是您的应用程序直接使用的地址。然后按照上面的两步将它们转换成RAM将理解的内容,物理地址。

    在第一步中,GDT(或者它可以是LDT,取决于选择器值)由选择器索引,以找到相关段的基址和大小。虚拟地址将是段基址和偏移量之和。需要段大小和段描述符中的其他内容来提供保护。

    在第二步中,页表由虚拟地址的不同部分编制索引,层次结构中的最后一个索引表给出了在地址总线上输出的最终物理地址,供RAM查看。与段描述符一样,页表条目不仅包含地址,还包含保护控制位。

    这就是关于机制的。

    现在,在许多x86操作系统中,用于应用程序的段选择器是固定的,它们在所有应用程序中是相同的,它们永远不会改变,它们指向基本地址等于0且大小等于可能的最大值(例如,非64位模式下为4GB)。这样的GDT设置实际上意味着第一步没有任何有用的工作,逻辑地址的偏移部分转换为数值相等的虚拟地址。

    这使得段选择器值几乎无用。它们仍然必须加载到CPU的段寄存器中(在非64位模式下至少加入CS,SS,DS和ES),但除此之外,它们可能会被遗忘。

    所有这些(除了与Linux相关的详细信息和ELF格式)都在英特尔和AMD的x86 CPU手册中进行了解释或直接说明。你会在那里找到更多细节。

答案 2 :(得分:0)

也许阅读Assembly HOWTO。当Linux进程开始使用execve system call执行ELF可执行文件时,它基本上(有点)mmap - 一些段(并初始化寄存器,以及一小部分堆)。另请阅读SVR4 x86 ABI supplement及其x86-64 variant。不要忘记Linux进程只看到address space的内存映射,只关心virtual memory

Operating Systems(= O.S。)kernels上有很多好书,特别是A.Tanenbaum&由M.Bach提供,有些在linux kernel

注意:Linux上几乎(几乎)未使用段寄存器。