在运行时存储程序的机器指令?

时间:2015-01-29 15:01:35

标签: c++ memory-management

据我所知,每当我们运行任何程序时,程序的机器指令都会加载到RAM中。同样,有两个内存区域:堆栈和堆。

我的问题是:机器指令存储在哪个内存区域?堆栈还是堆?

我了解到,虽然函数内部没有声明变量,但以下程序会产生运行时错误。这背后的原因是堆栈溢出。那么我应该假设函数的机器指令存储在堆栈中吗?

int func()
    {
            return func();
    }

7 个答案:

答案 0 :(得分:9)

两者都没有,因为它不是以动态动态分配堆栈和堆的方式。

可执行加载程序将可执行文件(.text)及其包含的任何静态数据(如全局变量的初始值(.data / .rodata))加载到未使用的RAM区域中。然后它设置可执行文件要求的任何零初始化内存(.bss)。

只有然后是为main()设置的堆栈。如果输入另一个函数,堆栈内存在堆栈上分配,包含返回地址,函数参数和任何本地声明的变量以及通过alloca()分配的任何内存。[1]从函数返回时释放内存。

堆内存由malloc()calloc()realloc()分配。它会在您free()realloc()时发布。

用于可执行文件的RAM及其静态数据在进程终止之前不会被释放。

因此,堆栈和堆基本上是在应用程序的控制之下。可执行文件本身的内存受可执行加载程序/操作系统的控制。在配备适当的操作系统中,您甚至无法对该内存进行写访问。


关于您编辑的问题,没有。 (糟糕的风格,编辑一个问题,给它一个全新的角度。)

可执行代码仍保留在加载位置。 调用函数将机器指令放在堆栈上。你的func()(一个没有参数的函数)唯一存在于堆栈上的是返回地址,这是一个指示当前函数返回后执行应该继续的位置的指针。

由于所有调用都没有返回,因此您的程序会不断在堆栈上添加返回地址,直到它不再存在为止。这根本与机器代码指令无关。


[1]:请注意,这些实际上并不是C语言标准的一部分,而是实现定义的,并且可能不同 - 我提供了事务的简化版本。例如,函数参数可能在CPU寄存器中传递,而不是在堆栈中传递。

答案 1 :(得分:3)

既不是一个也不是另一个。

程序的图像包含代码和静态数据(例如,所有字符串常量,静态数组和结构等)。它们将被加载到RAM的不同部分。

堆栈和堆是用于存储数据的动态结构,它们将在程序开始时创建。 Stack是硬件支持的解决方案,而heap是标准库支持的解决方案。

因此,您的代码将位于代码段中,您的静态数据和堆将位于数据段中,并且堆栈将位于堆栈段中。

答案 2 :(得分:2)

  

程序的机器指令加载到RAM中

正确托管,#34; PC-like"系统。在嵌入式系统上,代码通常直接从闪存中执行

  

同样,存在两个内存区域:堆栈和堆。

不,这种过度简化太多了,编程老师教的方式太糟糕了。

还有很多其他区域:.data.bss其中所有带静态存储的变量都去,.rodata其中常量等等等。

存储程序代码的段通常称为.text

答案 3 :(得分:1)

无论是堆还是堆栈。

通常,可执行指令存在于Code segment

引用维基百科文章

  

在计算中,代码段(也称为文本段或简称为文本)是目标文件的一部分或程序虚拟地址空间的相应部分,其中包含可执行指令。

  

当加载程序将程序放入内存以便执行时,会分配各种内存区域(特别是作为页面)

在运行时,目标文件的代码段被加载到内存中的相应代码段中。特别是,它与堆栈或堆无关。


编辑:

在上面的代码段中,您遇到的内容称为无限递归

即使你的功能在局部变量的堆栈中不需要任何空间,仍然需要推送 外部的返回地址在调用内部函数之前的函数,从而声称堆栈空间,永远不会return [弹出堆栈中的地址] [如 at a不归点],从而耗尽堆栈空间,导致堆栈溢出。

答案 4 :(得分:1)

  

同样,存在两个内存区域:堆栈和堆。

这不是那么简单。通常在主流操作系统上会有更多的东西在继续:

  • 每个正在运行的线程有一个堆栈;
  • 你决定分配多少堆(实际上,就内存管理器而言,你要求在你的虚拟地址空间中“启用”某些内存页面时,“堆”的东西来自于通常的事实一个使用某种堆管理器代码在分配之间有效地分配这些内存部分);
  • 可以有内存映射文件和共享内存;
  • 最重要的是,可执行文件(和动态库)映射到进程的内存中,通常是以只读模式映射的代码区(所谓的“文本”段)和其他区域(通常关于初始化的全局和静态变量以及由加载器修复的东西,在copy-on-write。

因此,代码存储在可执行文件的相关部分中,该部分映射到内存中。

答案 5 :(得分:1)

它们通常位于名为.text的部分。

在Linux上,您可以使用来自core-utils的size命令列出ELF对象或可执行文件的部分,例如tst ELF可执行文件:

$ size -Ax tst | grep "^\.text"
.text                0x1e8   0x4003b0
$

答案 6 :(得分:1)

除了堆栈和堆之外,还有多个内存段。以下是程序如何在内存中布局的示例:

              +------------------------+
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)中,未初始化的全局变量存储在另一个段中segment(.bss)等。某些段是只读的,有些是可写的。