3

我在 OSDev wiki 上读到,x86 架构的保护模式允许您为代码和数据创建单独的段,而您不能写入代码段。Windows(是的,这是平台)将新代码加载到代码段中,并在数据段上创建数据。但是,如果是这种情况,程序如何知道它必须将段切换到数据段?因为如果我理解正确,所有地址指令都指向您运行代码的段,除非您切换描述符。但我也读到,如此整理的平面内存模型允许您在一个段内运行代码和数据。但我仅在与汇编程序相关的情况下阅读此内容。那么,请问,Windows 上的 C 编译代码是什么情况?谢谢。

4

2 回答 2

3

解释中segment有两种含义:

  • 一个 8086 内存地址段
  • 目标模块程序段段

第一个与加载到 80386+ 段寄存器中的内容有关;它包含物理内存起始地址、内存分配长度、允许的读/写/执行访问,以及它是否从低到高或反之亦然(加上一些更模糊的标志,如“引用时复制”)。

第二个含义是对象模块语言的一部分。基本上,有一个名为 的段code,一个名为 的段data(其中包含已初始化的数据),以及一个用于未初始化数据的段,名为bss(以 1960 年代汇编程序的伪指令命名,意为以符号开头的块)。当链接器组合目标模块时,它会将所有代码段排列在一起,将所有数据段排列在别处,并将 bss 排列在一起。当加载器映射内存地址时,它会查看总代码空间并分配至少该大小的 CPU 内存分配,并将段映射到代码(在虚拟内存情况下)或将代码读入分配的内存中——为此它必须临时将内存设置为数据可写。写保护是通过 CPU 的分页机制以及段寄存器来完成的。这是为了保护代码写入尝试,例如通过错误的数据地址。加载器也对两个数据段组进行类似的设置。(除此之外,还有设置堆栈段并分配它,以及映射共享图像。)

就 x86 执行指令而言,每个操作数都有一个关联的段寄存器。有时这些是明确的,有时它们是隐含的。代码通过CS, stack隐式访问,SS只要涉及ESPorEBP寄存器就隐含通过它,并且DS对于大多数其他操作数也是隐含的。 ES, FS, andGS必须在所有其他情况下指定为覆盖,除了一些字符串指令,如movsand cmps。在平面模型中,所有段寄存器都映射到相同的地址空间,尽管 CS 不允许写入。

因此,为了回答您的最后一个问题,CPU 一次设置了四个(或更多)段寄存器来访问进程的平面虚拟内存空间。检查每个操作数访问是否适合指令(例如不增加CS地址),并且还由分页保护单元检查是否允许。

于 2010-05-02T18:14:25.837 回答
3

您阅读的信息已过时。1993 年以后的 Windows 版本使用平坦的 32 位虚拟内存空间。CS 和 DS 段寄存器的值不再重要且无法更改。仍然存在代码与数据的概念,现在由内存页面属性实现。查看在VirtualProtectEx() API 函数的 flNewProtect 参数中传递的允许值。

您自己很少使用此 API,属性由可执行映像加载器和堆管理器设置。

于 2010-05-02T19:03:41.303 回答