在 x86 中,.data 段是如何加载到一个单独的内存区域而不是 .code 段的?

How is the .data segment loaded into a seperate memory area than the .code segment in x86?

所以一直在摸索汇编,一直想知道,加载内核的时候,不同的段是怎么加载到不同的内存区的。我知道 OS 中的用户代码链接器和 OS 可以简单地将代码和数据放在他们想要的任何区域,但这个问题更具体到内核,内核没有OS 将.code 和.data 放到不同的区域。

假设我有一个简单的内核:

.data
var dw 123

.code
mov eax ebx

引导加载程序或任何处理此问题的程序如何将内核代码实际加载到数据的单独区域中? 并假设我有 5 个不同的汇编文件,都带有 .data 段,变量是否都一个接一个地加载到同一区域?

这由引导加载程序来处理,因此它最终取决于引导加载程序的作用,但通常引导加载程序加载标准格式(如 PECOFF 或 ELF)的标准可执行映像。它们加载内核很像操作系统加载程序可执行文件。

部分存在,因此具有相同名称的部分的内容将在可执行文件中全部连续组合在一起。链接器将获取所有输入目标文件中所有 .text 部分的内容,并将它们合并到输出可执行文件中的一个 .text 部分中。同样,它将对 .data 和其他命名部分执行相同的操作。

链接器获取所有这些组合部分并将它们一个接一个地放置在可执行文件中,创建一个可以加载到内存中的连续映像。在操作系统下,可执行文件将以一个连续的块的形式加载到内存中。如有必要,将应用重定位以说明可执行文件加载到与预期加载位置不同的地址,并且未初始化的数据段 (.bss) 将初始化为零。最后,内存中可执行文件的每一页的权限将根据它们所属的段进行调整。例如,.text 部分中的页面将被标记为只读和可执行,而在 .data 部分中它们将被标记为 read/write 且不可执行。

(请注意,这简化并掩盖了链接器和操作系统如何创建和加载可执行文件的许多细节。可以合并、重命名、丢弃部分等。可以在段之间插入填充 space因此它们是页面对齐的。在 ELF 下,目标文件中的命名部分实际上是可执行文件中未命名的程序段的转换,正是这些程序段决定了页面权限。)

引导加载程序加载内核可执行文件很像操作系统,但可能不支持重定位,并且不会更改页面权限,因为这些需要操作系统才能工作。内核本身负责设置自己的页面权限。

因此内核代码和数据被加载到一个单独的连续内存区域,该内存区域被细分为代码、数据和内核使用的任何其他部分的单独区域。