将内存分为代码段和数据段的基本原理是什么?我在一个来源中读到,由于冯诺依曼架构指令和数据存储在同一个地方,因此完成了这种分离。
但我想知道,由于指令和数据存储在同一个地方,因此需要分为代码段和数据段,可能会导致哪些问题?
为什么还要进一步进入bss段、堆段和堆栈段?
将程序分为代码和数据部分的最大好处之一是它允许代码部分变为只读,而数据部分可以保持可写。这可以保护代码段不被程序意外修改,并且还允许它在运行同一程序的进程之间共享。
最近,仅允许执行代码段中的代码的能力变得很重要。这是因为许多漏洞利用依赖于能够在代码段之外执行代码。分离代码和数据的另一个最近的好处是,如果代码和数据混合在一起,无序的 CPU 可能最终会推测性地执行数据,从而导致性能较差。
bss 部分作为数据部分的扩展而存在。它包含初始化为零的所有程序数据。通过像这样将零初始化数据分离出来,它允许 bss 部分实际上不存储在程序的可执行文件中。两者都节省磁盘空间并加快加载速度。内存中的 bss 部分只是用零填充,而不是将其读入内存。
堆和堆栈的相似之处在于它们都用于在程序运行时动态分配对象。两者之间的区别在于,分配在堆上的对象可以随时释放,而放入堆栈的任何对象只有在移除后才可以移除放入堆栈的所有对象。每次调用函数时,都会在堆栈上分配空间,用于存放函数参数、返回地址和局部变量等内容。当函数返回时,这些东西将从堆栈中删除。几乎任何其他动态分配的东西都是在堆上分配的。
传统上,在 Unix 系统上,堆位于内存中 bss 部分之后,而 bss 部分出现在代码和数据部分之后。当东西在堆上分配时,它会向上增长,以便根据需要为它们腾出空间。堆栈位于内存末尾,并向下增长。