2

我对 C 程序的内存布局有一些疑问。

文本段

这是我的第一个问题:

当我搜索文本段(或代码段)时,我读到“文本段包含可执行指令”。ut 任何功能的可执行指令是什么?你能举一些不同的例子吗?

我还读到“文本段是可共享的,因此对于频繁执行的程序(例如文本编辑器、C 编译器等),只需在内存中保存一个副本”,但我无法在 C 程序和“文本编辑器”。

我应该从这个声明中理解什么?

初始化数据段

据说“初始化数据段”包含全局变量和静态变量,但我也读到了const char* string = "hello world"使字符串文字“hello world”存储在初始化的只读区域和初始化读取的字符指针变量字符串-写区。char* string是存储只读区还是读写区?由于两者都写在这里,我有点困惑。

据我了解,堆栈包含局部变量。这是正确的吗?

4

4 回答 4

3

文本段包含程序的实际代码,即编译器发出的机器代码。最后一条语句的想法是,你的 C 程序和文本编辑器是完全一样的。它只是从内存中执行的机器代码指令。

例如,我们将采用以下代码,以及我刚刚想到的假设架构,因为我不记得 x86 汇编了。

while(i != 10)
{
    x -= 5;
    i++;
}

这将转化为以下说明

LOOP_START:
CMP eax, 10    # EAX contains i. Is it 10?
JZ  LOOP_END   # If it's 10, exit the loop
SUB ebx, 5     # Otherwise, subtract 5 from EBX (x)
ADD eax, 1     # And add 1 to i
JMP LOOP_START # And then go to the top of the loop.

LOOP_END:
# Do something else

这些是您的处理器可以理解的低级操作。然后这些将被翻译成二进制机器代码,然后存储在内存中。例如,考虑到我刚刚想到的操作和操作码之间的映射,实际存储的数据可能是 5、2、7、6、4、9。有关这实际上是如何发生的更多信息,请查看汇编程序和机器代码之间的关系。

-- Ninja-edit - 如果您接受上面 RBK 的评论,您可以使用 objdump 或类似的反汇编程序查看构成您的应用程序的实际说明。Visual Studio 中有一个,或者您可以在 Windows 上使用 OllyDbg 或 IDA。

因为程序的实际指令应该是只读的,所以不需要为程序的多次运行复制文本段,因为它应该始终相同。

至于您对数据段的问题,char* string实际上将存储在该.bss段中,因为它没有初始化程序。这是在程序运行之前(通过 crt0 或等效项)清除的内存区域,除非您给 GCC 一个我不记得的标志。该.bss段是可读写的。

是的,堆栈段包含您的局部变量。实际上,它存储所谓的“堆栈帧”。其中一个是为您调用的每个函数创建的,它们相互堆叠。正如您所说,它包含诸如局部变量之类的内容,以及其他有用的位(例如调用函数的地址)以及其他有用的数据,以便在函数退出时可以恢复以前的状态。对于堆栈框架中实际包含的内容,您需要深入研究架构的 ABI(应用程序二进制接口)。

于 2013-05-29T13:45:12.043 回答
1

文本段通常也称为“代码”(“文本”往往是 Unix/linux 名称,其他操作系统不一定使用该名称)。

从某种意义上说,如果您运行两个都执行 C 编译器的进程,或者您在两个不同的窗口中打开文本编辑器,那么这两个进程共享相同的“文本”部分,因为它在代码的运行(文本段中不允许自修改代码)。

初始化的字符串值存储在“ro-data”或“text”中,具体取决于编译器。是的,它不可写。

如果string是一个全局变量,它将以“初始化数据”结束,它将保存“hello world”消息的地址string。这const部分是指指针指向的内容是恒定的,因此我们实际上可以在string = "foo bar";后面的代码中更改指针。

实际上,堆栈用于局部变量,并且通常用于调用堆栈(代码在完成当前函数后返回到该堆栈)。

于 2013-05-29T13:53:43.227 回答
1

但是,程序的内存中映像的实际布局完全取决于操作系统,通常也取决于程序本身。然而,从概念上讲,我们可以为正在运行的程序考虑两段内存[1]。

  1. 文本或代码段 - 包含已编译的程序代码。
  2. 数据段 - 包含已初始化和未初始化的数据(全局、静态和本地)。数据段可以进一步细分如下:

    2.1 初始化数据段
    2.2 未初始化数据段
    2.3 堆栈段
    2.4 堆段

    初始化数据段存储所有预先初始化的全局变量、静态变量、常量变量和外部变量(用 extern 关键字声明)。

    未初始化的数据段或 .bss 段存储所有未初始化的全局、静态和外部变量(用 extern 关键字声明)。

    堆栈段用于存储所有局部变量,用于将参数与函数调用结束后要执行的指令的返回地址一起传递给函数。

    堆段也是存储动态分配变量的 RAM 的一部分。

    来到你的第一个问题 - 如果你知道函数指针,那么你知道函数名返回函数的地址(这是该函数的入口点)。这些指令在汇编中编码。指令集可能因架构而异。

文本或代码部分是可共享的 - 如果多个正在运行的进程属于同一个程序,则不需要将公共编译代码单独加载到内存中。例如,如果您打开了两个 .doc 文档,那么它们将有两个进程,但肯定会有一些共同的代码被两个进程使用。

于 2013-12-27T12:23:37.140 回答
0

堆栈段是存储局部变量的区域。所说的局部变量是指所有在每个函数中声明的变量,包括 C 程序中的 main()。

当我们调用任何函数时,会创建堆栈帧,当函数返回时,会销毁堆栈帧,包括该特定函数的所有局部变量。

堆栈帧包含一些数据,如返回地址、传递给它的参数、局部变量以及被调用函数所需的任何其他信息。

“堆栈指针(SP)”通过对堆栈的每次推送和弹出操作,通过调整堆栈指针到下一个或前一个地址来跟踪堆栈。

您可以参考此链接以获取实用信息:- http://www.firmcodes.com/memory-layout-c-program-2/

于 2015-02-11T14:02:08.230 回答