我的问题是:机器指令存储在哪个内存区域中?堆栈还是堆?
我了解到,尽管函数内没有声明变量,但以下程序会导致运行时错误。这背后的原因是堆栈溢出。那么我是否可以假定该函数的机器指令存储在堆栈中?
int func()
{
return func();
}
int func()
{
return func();
}
因为它不像堆和栈一样是动态分配的,所以它不属于动态分配。
可执行文件(.text)和它包含的任何静态数据,例如全局变量的初始值(.data/.rodata),将被装载到未使用的RAM区域。然后,设置可执行文件请求的任何零初始化内存(.bss)。
只有在这之后,才会设置main()
的栈。如果您进入另一个函数,则在栈上分配堆栈内存,保留返回地址、函数参数和任何本地声明的变量以及通过alloca()
分配的任何内存[1]。当您从该函数返回时,释放内存。
堆内存由malloc()
,calloc()
或realloc()
分配。当您使用free()
或realloc()
释放内存时,堆内存将被释放。
用于可执行文件及其静态数据的RAM直到进程终止才会被释放。
因此,栈和堆基本上受应用程序控制。可执行文件本身的内存受可执行文件加载器/操作系统控制。在适当配置的操作系统中,您甚至无法写入该内存。
关于您编辑的问题,答案是否定的(风格不佳,编辑一个问题给它一个完全不同的角度)。
可执行代码仍然留在加载它的位置。调用函数不会将机器指令放置在堆栈上。您的func()
(一个不带参数的函数)放置在堆栈上的唯一内容是返回地址,一个指针,它指示在当前函数返回后执行应该继续进行的位置。
由于没有任何调用返回,您的程序会一直在堆栈上添加返回地址,直到无法再添加为止。这与机器代码指令毫无关系。
[1]: 注意,这些并不是C语言标准的一部分,而是实现定义的内容,可能会有所不同——我展示的是一个简化版的情况。例如,函数参数可能会被传递到CPU寄存器中,而不是在堆栈上。
既非前者也非后者。
你的程序镜像包含了代码和静态数据(例如所有字符串常量、静态数组、结构等),它们将被加载到内存的不同段中。
堆和栈是动态的数据结构,用于存储数据,它们将在程序启动时创建。栈是硬件支持的解决方案,而堆是标准库支持的解决方案。
因此,你的代码将位于代码段,静态数据和堆将位于数据段,而栈将位于栈段。
程序的机器指令被加载到RAM中。
对于托管的"类PC"系统而言,这是正确的。在嵌入式系统上,代码通常直接从闪存中执行。
同样,存在两个内存区域:堆和栈。
不,这是过于简化的表述,许多糟糕的编程教师都会这样教。除此之外,还有很多其他区域:所有具有静态存储的变量所在的.data
和.bss
区域,常量所在的.rodata
区域等等。
存储程序代码的段通常称为.text
。
+------------------------+
high address | Command line arguments |
| and environment vars |
+------------------------+
| stack |
| - - - - - - - - - - - |
| | |
| V |
| |
| ^ |
| | |
| - - - - - - - - - - - |
| heap |
+------------------------+
| global and read- |
| only data |
+------------------------+
| program text |
low address | (machine code) |
+------------------------+
不同平台的细节会有所不同,但这种布局在基于x86的系统中非常普遍。机器代码占据自己的内存段(在ELF格式中标记为.text
),全局只读数据将存储在另一个段中(.rdata
或.rodata
),未初始化的全局变量在另一个段中(.bss
)等。一些段是只读的,一些是可写的。
既非堆栈也非堆。
通常,可执行指令位于代码段中。
引用维基百科文章
在计算机中,代码段(也称为文本段或简称为文本)是对象文件的一部分或程序虚拟地址空间的相应部分,其中包含可执行指令。
和
当加载器将程序放入内存以便执行时,将分配各种内存区域(特别是页)
运行时,对象文件的代码段被加载到内存中对应的代码段中。特别地,它与堆栈无关。
编辑:
在您上面的代码片段中,您遇到的是所谓的无限递归。
即使您的函数不需要堆栈中的任何本地变量空间,它仍然需要推入外部函数的返回地址,然后调用内部函数,从而声明堆栈空间,但永远不会返回
[弹出地址以腾出堆栈空间] [就像在不可回溯的点一样],从而导致堆栈溢出。
.text
的部分。size
命令列出ELF对象或可执行文件的各个部分。例如,在tst
ELF可执行文件上:$ size -Ax tst | grep "^\.text"
.text 0x1e8 0x4003b0
$