Linux内核逻辑地址空间组织

gkt*_*gkt 8 linux kernel memory kernel-modules

根据“编写伟大的代码”,几乎所有操作系统运行时内存都被组织成以下区域:

操作系统 | 堆栈 | 堆 | 文字 | 静态 | 存储/BSS

[以增加地址方式]

用户空间进程为其不同类型的数据对象使用更高的内存区域。

内核空间进程也有不同类型的数据对象。这些对象是否共享用户空间内存区域(堆栈、堆等),或者它们是否在操作系统区域中有自己的独立子部分(堆、堆栈等)。如果是,它们的排列顺序是什么? . 谢谢,

psu*_*usi 5

顺序错了。操作系统位于内存顶部,在32位内核中一般在3 GB标记( 0xC0000000 )之上,在64位内核中是0x8000000000000000 IIRC的中点。

堆栈和堆的位置是随机的。关于主程序中 text/data/bss 段的顺序没有真正的规则,每个动态库都有自己的一组这些,所以有很多它们分散在内存中。

回到恐龙统治地球时(20 多年前),程序地址空间是线性的(没有空洞),顺序是文本、数据、bss、堆栈、堆。那时也没有动态库或线程。这一切都随着虚拟内存而改变。

内核进程完全包含在地址空间的内核部分;用户部分被忽略。这允许内核加速内核线程之间的上下文切换,因为它不必更新页表,因为所有进程共享页表的相同内核部分。


小智 1

不是答案,而是需要更多空间的仅供参考。

我认为您的逻辑地址布局概念根本不正确。

您可以编译并运行该程序来查看用户态进程的地址:

#include <stdio.h>
long global_initialized = 119234;
long global_uninitialized;
extern int _end, _edata, _etext;
int
main(int ac, char **av)
{
        long local;

        printf("main at 0x%lx\n", main);
        printf("ac at   0x%lx\n", &ac);
        printf("av at   0x%lx\n", &av);
        printf("av has  0x%lx\n", av);
        printf("initialized global at 0x%lx\n", &global_initialized);
        printf("global at             0x%lx\n", &global_uninitialized);
        printf("local at              0x%lx\n", &local);
        printf("_end at               0x%lx\n", &_end);
        printf("_edata at             0x%lx\n", &_edata);
        printf("_etext at             0x%lx\n", &_etext);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

我运行的 Red Hat Enterprise Server 有readelf,它可以用来表示内核将(逻辑上)加载可执行文件的位置:

readelf -S where
Run Code Online (Sandbox Code Playgroud)

向我显示了许多与 的输出where给出的相同的寻址信息。

我认为在 Linux 内核(/boot/vmlinuz 或类似的内核)上工作并不readelf容易,并且我认为内核默认在其自己的地址空间中从 0x80000000 开始:它没有映射到用户态进程中,尽管使用了用户态堆栈顶部上方的地址位于 0x7fffffff(x86,32 位寻址)。