C编译程序使用哪些段?

时间:2010-05-02 17:33:16

标签: c windows memory-segmentation

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

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

解释中 segment 有两个含义:

  • 8086内存地址段
  • 对象模块程序部分段

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

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

就x86执行指令而言,每个操作数都有一个相关的段寄存器。有时这些是明确的,有时它们是隐含的。通过CS隐式访问代码,通过SS进行堆栈,只要涉及ESPEBP寄存器,就会隐含代码,而对于大多数其他操作数,隐含DS 。除ESFS等字符串指令外,必须在所有其他情况下将GSmovscmps指定为覆盖。在平面模型中,所有段寄存器都映射到相同的地址空间,但CS不允许写入。

因此,为了回答您的上一个问题,CPU会立即设置四个(或更多)段寄存器来访问进程的扁平虚拟内存空间。检查每个操作数访问是否适合该指令(如不增加CS地址),并且寻呼保护单元也检查是否允许该操作。