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

Where machine instructions of a program stored during runtime?

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

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

我了解到下面的程序给出了 运行time 错误,尽管函数内部没有声明变量。这背后的原因是堆栈溢出。那我应该假设函数的机器指令存储在堆栈中吗?

int func()
    {
            return func();
    }

都不是,因为它不是动态分配堆栈和堆的方式。

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

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

堆内存由malloc()calloc()realloc()分配。当您 free()realloc() 时它会被释放。

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

因此,栈和堆基本上都在应用程序的控制之下。可执行文件本身的内存在可执行加载程序/操作系统的控制之下。在配备适当的操作系统中,您甚至没有对该内存的写入权限。


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

可执行代码保留在加载的位置。 调用函数不会将机器指令放入堆栈。你的func()(一个不带参数的函数)唯一放在堆栈上的是return地址,一个指示一旦当前执行应该继续执行的指针函数 returns.

自从 none 次调用以来 return 秒,您的程序一直在堆栈上添加 return 个地址,直到无法容纳为止。这与机器代码指令完全无关。


[1]:请注意,none 实际上是 C 语言标准的重要组成部分,但是 实现定义的 ,并且可能有所不同——我呈现了事务的简化版本。例如,函数参数可能在 CPU 寄存器中传递,而不是在堆栈中传递。

既不是堆也不是栈。

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

引用维基百科文章

In computing, a code segment, also known as a text segment or simply as text, is a portion of an object file or the corresponding section of the program's virtual address space that contains executable instructions.

when the loader places a program into memory so that it may be executed, various memory regions are allocated (in particular, as pages)

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


编辑:

在您上面的代码片段中,您遇到的是所谓的无限递归

即使您的函数不需要任何 space 堆栈中的局部变量,它 仍然需要 push return在调用 inner 函数之前,outer 函数的地址,从而声明堆栈 space,只是永远不会 return [弹出地址出栈] [像在没有return的地方],因此运行出栈space,导致栈溢出

两者都不是。

您的程序映像包含代码和静态数据(f.e。所有字符串常量、静态数组和结构等)。它们将被加载到 RAM 的不同部分。

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

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

Again, there is two regions of memory: stack and heap.

没那么简单。通常在主流操作系统上会发生更多事情:

  • 每个 运行 线程有一个堆栈;
  • 你决定分配多少堆(实际上,就内存管理器而言,你在你的虚拟地址 space 中请求一些内存页到 "enabled", "heap" 事情源于这样一个事实,即通常使用某种堆管理器代码在分配之间有效地分配这些内存部分);
  • 可以有内存映射文件和共享内存;
  • 最重要的是,可执行文件(和动态库)映射到进程的内存中,通常以只读模式映射代码区(所谓的 "text" 段),并且写时复制中的其他区域(通常与初始化的全局和静态变量以及加载程序修复的内容有关)。

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

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

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

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

the machine instructions of the program is loaded in RAM

适用于托管的 "PC-like" 系统。在嵌入式系统上,代码通常直接从闪存中执行

Again, there is two regions of memory: stack and heap.

不,这过于简单化了,编程老师教的太多了,太糟糕了。

还有很多其他区域:.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),未初始化的全局变量在另一个segment (.bss) 等。有些段是只读的,有些是可写的。