2015-12-31 210 views
2

我最近试图想象如何在Linux内核中处理堆栈内存,但无法提供任何可靠的东西。我知道内核使用自己的函数进行动态内存管理,但是我不知道它是如何管理普通的C堆栈内存的,因为毕竟,这可以用普通的C实现并且用普通的GCC编译。就我而言,堆栈内存分配通常在处理操作系统时甚至在处理AVR时通过libc的形式处理。据我所知,尽管Linux内核不依赖于libc?Linux内核中的堆栈内存

我不能完全肯定的内存管理是如何栈委托摆在首位到libc虽然它似乎是一个语言功能构建的。我可以想像的是,它以某种方式编译(或实现),以便提供者可以在之后或可能作为编译过程的一部分被分配。有人可以帮我解释一下吗?

+0

当一个新进程启动时,它有一个映射到进程地址空间的用户空间堆栈和一个用于进行系统调用的内核堆栈。堆栈指针开始指向堆栈。 libc并没有参与这个* *。发布的答案有点令人困惑,但它似乎是正确的关于ELF二进制文件能够控制他们得到什么样的堆栈设置:http://stackoverflow.com/questions/18278803/how-does-elf-file-format - 定义最堆栈。缺省情况是不具有这样的部分,然后在内核默认的virt地址选择处获得默认堆栈。 –

回答

0

至于我拥有它,堆内存分配由 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); 
} 

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

0

堆内存被分配在链接步骤(整个堆叠)。

堆栈存储器(通常)放置在.STACK段(其只不过是一个偏移量和长度更大,没有内容)。

.startup代码(通常是某个库中的汇编函数,我不确定哪个库)会在加载的代码中找到.stack节的名称,并添加长度值以获取堆栈的顶部地址(堆栈向下增长)和(在其他几个操作中)设置寄存器spbp。当操作系统运行时(I.E.不处于'用户'模式),它(通常)具有其自己的堆栈空间,并使用其自己的值作为spbp寄存器的值。

“用户”模式和“特权”模式和寄存器值的交换之间的切换是在转变之间的你写什么,在内核代码进行处理。

大部分此类切换都在libc库中的包装函数中进行处理,并且生成的控件会通过跳转到内核例程的表格进行转换。

注:其它的CPU和操作系统有关于事物是如何实现的细节别共,但结果非常相似。

+0

我在现代linux中找不到.stack段。 '%objdump -h/bin/cat' –

+0

也许你可以阅读这个stackoverflow问题来找到你正在寻找的答案: user3629249

+1

保存/恢复寄存器,并交换到内核堆栈,*不*由libc处理。内核不能信任libc,因为libc只是非特权进程运行的用户空间代码!而且,当你直接进行系统调用时(例如在64位模式下使用“syscall”指令),即使对于不链接任何库的玩具可执行文件,它也必须发生并且工作相同。 –

0

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

在UNIX的土地,运行的程序是一个两个步骤的过程。首先,你克隆一个父进程。因此,新进程与父进程具有相同的堆栈设置。

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

启动后,应用程序可以调用系统服务来分配内存页面,并具有堆栈指针寄存器引用。然后,这成为程序堆栈。

请记住,这一切都指的是用户堆栈。操作系统为每个进程使用它自己的目的维护一个KERNEL堆栈。