在 x64 上,Linux 内核如何访问数据段?它在编译期间是否使用 -mcmodel=large?

On x64, how does the Linux kernel access the data segment? Does it use -mcmodel=large during compilation?

我正在从头编写一个最小的 x86-64 内核,但遇到了一些设计问题。

根据 stark 提供的评论和 link,我决定重新表述我的问题。我想以Linux内核为例来设计我自己的内核,希望得到一些建议。

我知道,当编译 C++ 代码时,它将默认使用 RIP 相对寻址来访问可执行文件的数据段(对于所有 global/static 变量)。 RIP 相对寻址被限制为 32 位偏移量,它与代码段的最大偏移量为 2GB。

我也知道(从 stark 的评论中)Linux 内核在 0xffff_ffff_8000_0000 (https://www.kernel.org/doc/html/latest/x86/x86_64/mm.html):

开始它的代码段
ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0

如果 Linux 内核的代码段距离其大部分数据段超过 2GB,除了使用 RIP 相对寻址之外,它如何访问它?

我认为 -mcmodel=kernel 代码模型可以将 32 位绝对地址符号扩展到 64 位,这允许可执行文件访问虚拟地址的高 2GB space 而无需使用 -mcmodel=large .这无济于事,因为在该区域找不到内核的数据段。同时,-mcmodel=large 使可执行文件使用 64 位绝对地址访问数据段,这会减慢内核速度并使其变得更大。

Linux内核如何访问数据段,是否使用大代码模型访问虚拟地址space的0xffff_8000_0000_0000区域?

我认为混淆是在 gcc 内存模型和 64 位 CPU 的 MMU 之间。使用内核内存模型生成的代码使用带符号的 32 位偏移量,这意味着内核中的所有符号都必须适合地址 space 的前 2GB。这不会改变内核中的虚拟地址指针是 64 位的事实,其中 48 位左右是有效的,允许通过页表和 MMU 间接访问内核或当前用户 space 中的任何内容.