【问题标题】:Stack memory inside the Linux kernelLinux内核中的堆栈内存
【发布时间】:2016-04-05 04:46:31
【问题描述】:

我最近试图想象堆栈内存在 Linux 内核中可能是如何处理的,但我想不出任何可靠的东西。我知道内核使用自己的函数进行动态内存管理,但我不知道它是如何管理普通 C 堆栈内存的,因为毕竟可以用普通 C 实现并用普通 GCC 编译。据我所知,在处理操作系统甚至像 AVR 之类的东西时,堆栈内存分配通常由一种 libc 形式处理。据我所知,虽然 Linux 内核不依赖于 libc?

我不完全确定堆栈内存管理首先是如何委托给 libc 的,因为它似乎是一种内置的语言功能。我所能想象的只是它以某种方式被通用编译(或实现),因此可以在之后或可能作为编译过程的一部分分配提供者。有人可以帮我解释一下吗?

【问题讨论】:

  • 当一个新进程启动时,它有一个映射到进程地址空间的用户空间堆栈和一个内核堆栈,供它进行系统调用时使用。堆栈指针开始指向堆栈。 libc 根本不参与。发布的答案有些令人困惑,但 ELF 二进制文件能够控制它们获得的堆栈设置似乎是正确的:stackoverflow.com/questions/18278803/…。默认是没有这样的section,然后在内核默认选择的virt地址处得到一个默认栈。

标签: c linux memory-management linux-kernel


【解决方案1】:

据我所知,堆栈内存分配通常由 libc 的一种形式……

这个程序说明了 libc 中没有任何东西用于堆栈内存分配:

// compile with: gcc -nostdlib nolibc.c -o nolibc
_start()
{
    int a[9999];
    *a = 0;
    asm("   mov %0,%%ebx\n\
            mov $1,%%eax\n\
            int $128" : : "r" (*a));    // _exit(*a);
}

如果超出分配的堆栈空间,则会发生错误,并且内核的错误处理程序可以分配更多空间,除非达到限制或使用了固定大小。

【讨论】:

    【解决方案2】:

    堆栈可以是任何读/写内存块。堆栈没有什么特别之处。操作系统创建一个堆栈——即,它分配内存并将它的位置分配给堆栈指针寄存器——因为需要一个来启动 a 进程,但它不管理堆栈。

    在 unix-land 中,运行程序是一个两步过程。首先,您克隆父进程。因此,新进程与父进程具有相同的堆栈设置。

    最后,执行程序。程序加载从可执行文件中获取所需的堆栈大小,而可执行文件又从链接器获取信息(例如,参见 ld 命令的“堆栈”选项)。

    启动后,应用程序可以调用系统服务来分配内存页并让堆栈指针寄存器引用该内存页。然后就变成了程序栈。

    请记住,这都是指 USER 堆栈。操作系统为每个用于其自身目的的进程维护一个 KERNEL 堆栈。

    【讨论】:

      【解决方案3】:

      在链接步骤期间分配堆栈内存(整个堆栈)。

      堆栈内存(通常)放置在 .stack 段中(只不过是一个偏移量和长度,没有内容)。

      .startup 代码(通常是某个库中的汇编函数,我不确定是哪个库)在加载的代码中找到 .stack 部分的名称,添加长度值以获得堆栈的顶部地址(堆栈向下增长)和(在其他几个操作中)设置spbp 寄存器。

      当操作系统运行时(即不在“用户”模式下),它(通常)拥有自己的堆栈空间,并为spbp 寄存器使用自己的值。

      “用户”模式和“特权”模式之间的切换以及寄存器值的交换是在您编写的内容与内核中的代码之间的转换中处理的。

      大多数此类切换在 libc 库中的包装函数中处理,由此产生的控制通过跳转表进入内核例程。

      注意:其他 CPU 和操作系统在完成任务的细节上有所不同,但结果非常相似。

      【讨论】:

      • 我在现代 linux 中找不到 .stack 段。 % objdump -h /bin/cat
      • 也许你可以阅读这个 stackoverflow 问题来找到你正在寻找的答案:stackoverflow.com/questions/12911841/…>
      • 保存/恢复寄存器以及交换到内核堆栈,由 libc 处理。内核不能信任 libc,因为 libc 只是由非特权进程运行的用户空间代码!此外,当您“直接”进行系统调用(例如,在 64 位模式下使用 syscall 指令)时,它必须发生并且工作方式相同,即使对于不链接任何库的玩具可执行文件也是如此。
      • 堆栈内存在链接步骤中没有“分配”,它只是存储一个标记为默认堆栈大小的数字。堆栈内存是在操作系统加载程序时分配的,使用“堆栈大小”参数。
      • @crazii, 堆栈分配的参数是在链接时设置的。实际的内存分配是在加载时处理的。对不起,如果我说错了
      猜你喜欢
      • 2020-04-24
      • 2017-09-03
      • 2015-06-26
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      • 2014-05-20
      • 2017-01-29
      • 2017-09-19
      相关资源
      最近更新 更多