我对x86 linux机器中的分段和分页过程有一个混淆的概念。 如果有人澄清从开始到结束所涉及的所有步骤,会很高兴。
x86使用分页分段内存技术进行内存pipe理。
任何人都可以解释一下,从一个可执行.elf格式文件从硬盘加载到主内存到它死的时候发生了什么。 编译时,可执行文件有不同的部分(文本,数据,堆栈,堆,bss)。 这将如何加载? 如何在页面分割内存技术下build立起来。
想知道如何为加载的程序设置页表? 想知道如何GDT表设置。 如何加载寄存器? 为什么逻辑地址(MMU的分段单元处理的地址是48位(16位的段select器+ 32位的偏移量)),其他的16位是如何存储的呢?任何从ram访问的东西都必须是32位或4个字节,16位的其余部分如何被访问(要加载到段寄存器中)?
提前致谢。 这个问题可以有很多的事情。 但想要澄清一个可执行文件的整个生命周期。 如果有人回答并就此进行讨论,会很高兴。
没有像分页分割这样的东西,至少在官方文档中没有。 有两种不同的机制在一起工作,或多或少彼此独立:
16-bit segment selector value:16/32/64-bit segment offset value
的逻辑地址的转换16-bit segment selector value:16/32/64-bit segment offset value
,即一对2位数字转换为32/64-bit virtual address
。 virtual address
转换为32/64-bit physical address
。 逻辑地址是您的应用程序直接操作的地址。 然后按照上面的两步翻译的内容将RAM理解,物理地址。
在第一步中,GDT(或者它可以是LDT,取决于选择器的值)被选择器索引以找到相关的段的基地址和大小。 虚拟地址将是段基地址和偏移量的总和。 段描述符中的段大小和其他内容是需要提供保护的。
在第二步中,页面表由虚拟地址的不同部分索引,层次结构中的最后一个索引表给出了RAM在地址总线上出去的最终的物理地址。 就像段描述符一样,页表项不仅包含地址,还包含保护控制位。
这是关于机制。
现在,在许多x86操作系统中,用于应用程序的段选择器是固定的,它们全都是相同的,它们从不改变,它们指向基址等于0并且大小等于可能的最大值的段描述符例如在非64位模式下为4GB)。 这样的GDT设置有效地意味着第一步没有任何有用的工作,并且逻辑地址的偏移部分转换成数字上相等的虚拟地址。
这使段选择器的值几乎无用。 他们仍然必须加载到CPU的段寄存器(非64位模式,至少CS,SS,DS和ES),但超过这一点,他们可以被遗忘。
这一切(除了Linux相关细节和ELF格式)在Intel和AMD的x86 CPU手册中或直接介绍如下。 你会发现更多的细节。
Unix传统上已经通过分页来实现保护。 286+提供分段功能,386+提供分页功能。 每个人都使用分页,很少有人真正使用分段。
在x86中,每个内存操作数都有一个隐式段(因此地址实际上是16位选择器+ 32位偏移量),具体取决于所使用的寄存器。 因此,如果访问[ESP + 8]
,隐含段寄存器是SS
,如果访问[ESI]
,隐含段寄存器是DS
,如果访问[EDI+4]
则隐含段寄存器是ES
,…可以覆盖这个通过段前缀覆盖。
Linux和几乎所有的现代x86操作系统都使用了平坦的内存模型(或类似的东西)。 在平坦的内存模型下,每个段提供对整个内存的访问,基数为0,极限为4Gb,因此您不必担心分段带来的问题。 基本上有4个部分:内核空间代码(RX),内核空间数据(RW),用户空间代码(RX),用户空间数据(RW)。
一个ELF文件由一些标题组成,用于“编程分段”和“部分”。 部分用于链接。 程序段用于加载。 程序段通过mmap()
映射到内存中,这样就设置了具有适当权限的页表项。
现在,较早的x86 CPU的分页机制只提供了RW访问控制(读取权限意味着执行权限),而分段则提供了RWX访问控制。 结束权限考虑到分段和分页(例如:RW(数据段)+ R(只读页面)= R(只读),而RX(代码段)+ R(只读页面)= RX(读执行))。
所以有一些补丁提供了通过分段来防止执行:例如,OpenWall通过收缩代码段(具有执行权限的代码段)提供了一个不可执行的堆栈,并且在页面错误处理器中进行特殊的模拟,以处理需要从高处内存地址(例如:GCC蹦床,在堆栈上创建的自修改代码以有效实现嵌套功能)。
也许读了Assembly HOWTO 。 当一个Linux进程开始使用execve 系统调用来执行一个ELF可执行文件时,它本质上(有点)mmap-一些段(以及初始化寄存器和一小部分堆栈)。 另请阅读SVR4 x86 ABI补充资料及其x86-64版本 。 不要忘记,一个Linux进程只能看到它的地址空间的内存映射,只关心虚拟内存
有很多关于操作系统 (= OS) 内核的好书 ,特别是由A.Tanenbaum和M.Bach所着 ,还有一些关于Linux内核
注意:在Linux上几乎(几乎)没有使用段寄存器。