【问题标题】:Does a compiler have consider the kernel memory space when laying out memory?编译器在布局内存时是否考虑了内核内存空间?
【发布时间】:2016-10-26 08:00:09
【问题描述】:

我正在尝试调和一些概念。

我知道虚拟内存在内核和所有用户进程之间共享(映射),我读过here。我还知道,当编译器为代码+数据生成地址时,内核必须将它们加载到该进程的正确虚拟地址。

为了限制问题的范围,当我提到“编译器”时,我只是指 gcc。 那么编译器是否需要兼容操作系统的每个新版本,才能知道不要将代码或数据放在为内核保留的高内存地址?例如,编写该编译器的人必须知道内核计划如何加载程序的那些细节(以免编译器将可执行代码放在高内存中)?

还是我混淆了不同的概念?在查看this tutorial 时,我有点困惑,尤其是在最底层,它的 OS 代码位于低内存地址,因为我认为 Linux 将高内存用于内核。

【问题讨论】:

    标签: c gcc memory linux-kernel


    【解决方案1】:

    Linux 为每个应用程序提供与内核不同的内存空间。页表包含此内存空间和物理 RAM 之间的转换,内核设置页表,因此没有干扰。

    也就是说,编译器通常甚至不关心程序在内存中的加载位置。为什么会这样?

    【讨论】:

    • 我在想是否将 jmp 指令放入静态地址,或者如何知道静态/全局数据的位置。
    • 啊,第二次看,我看到全局数据是相对处理的,任何直接跳转根据定义也是相对的。
    【解决方案2】:

    编译器不会确定内存中放置东西的地址范围。这是由操作系统处理的。

    当程序第一次执行时,加载程序将程序的各个部分及其库放入内存中。对于动态分配的内存,大块是从操作系统分配的,然后有时会分成更小的块。

    操作系统加载器知道在哪里加载东西。以及操作系统的虚拟内存分配逻辑如何在进程使用的地址空间中找到安全的空白空间。

    我不确定您所说的“为内核保留的高内存地址”是什么意思。如果您谈论的是 32 位操作系统上的 2G/2G 或 3G/1G 拆分,那是使用它的操作系统的基本设计元素。它不会随版本而变化。

    如果您说的是高物理内存,那么不是。编译器不关心物理内存。

    【讨论】:

    • 两者之间通常还有一些不可见的胶水,许多编译器(或者更确切地说是链接器)通过链接器脚本指定内存布局,该脚本是为操作系统量身定制的 - 在内存中放置各个部分的位置一个可执行文件。
    • 对于 Linux,其实很简单:GCC 将代码放在大多数架构上的虚拟地址 0。
    • 你是对的。当我查看反汇编时,我似乎已经明白了,其中使用了直接(虚拟)地址并感到困惑。
    猜你喜欢
    • 2019-02-14
    • 1970-01-01
    • 2014-03-28
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    • 2014-11-13
    • 2013-10-06
    相关资源
    最近更新 更多