我最近试图想象堆栈内存可能是如何在Linux内核中处理的,但却无法提供任何可靠的东西。我知道内核使用自己的函数进行动态内存管理,但我不知道它如何管理正常的C堆栈内存,因为毕竟,这可以用普通的C实现并用普通的GCC编译。就我而言,堆栈内存分配通常在处理操作系统时甚至在像AVR这样的东西上由libc处理。据我所知,虽然Linux内核不依赖于libc?
我不完全确定如何将堆栈内存管理委托给libc,因为它似乎是内置语言功能。我可以想象的是,它通常以某种方式编译(或实现),以便可以在之后或可能作为编译过程的一部分分配提供者。有人可以帮我解释一下吗?
答案 0 :(得分:0)
在链接步骤中分配堆栈内存(整个堆栈)。
堆栈内存(通常)放在.stack段中(只不过是偏移和长度,没有内容)。
.startup代码(通常是某个库中的汇编函数,我不确定哪个库)在加载的代码中找到.stack部分的名称,添加长度值以获取顶部地址堆栈(堆栈向下增长)和(在其他几个操作中)设置sp
和bp
寄存器。
当操作系统运行时(I.E.不在'用户'模式),它(通常)有其'自己的堆栈空间并使用它的'拥有sp
和bp
个寄存器的值。
'用户'之间切换模式和特权'模式和寄存器值的交换是在你写的内容和内核中的代码之间的转换中处理的。
大多数此类切换都在libc
库中的包装函数中处理,结果控件通过跳转到内核例程的表进行转换。
注意:其他CPU和操作系统有关于如何完成工作的不同细节,但结果非常相似。
答案 1 :(得分:0)
堆栈可以是任何读/写内存块。堆栈没有什么特别之处。操作系统创建一个堆栈 - 即,它分配内存并将其分配给堆栈指针寄存器 - 因为需要一个启动进程,但它不管理堆栈。
在unix-land中,运行程序是一个两步过程。首先,克隆父进程。因此,新进程具有与父进程相同的堆栈设置。
最后,执行程序。程序加载从可执行文件中获取所需的堆栈大小,而可执行文件又从链接器获取信息(例如,参见ld命令的“stack”选项)。
启动后,应用程序可以调用系统服务来分配内存页面并使堆栈指针寄存器引用。然后它就成了程序堆栈。
请记住,这一切都指的是USER堆栈。操作系统为每个进程维护一个KERNEL堆栈,用于它自己的目的。
答案 2 :(得分: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);
}
如果超出分配的堆栈空间,则会发生故障并且内核的故障处理程序可以分配更多空间,除非达到限制或使用固定大小。