我对C程序的内存布局有一些疑问。
这是我的第一个问题:
当我搜索文本段(或代码段)时,我读到“文本段包含可执行指令”。什么是任何功能的可执行指令?你能举一些不同的例子吗?
我还读到“文本段是可共享的,因此只有一个副本需要在内存中用于频繁执行的程序,如文本编辑器,C编译器等”,但我无法在C之间建立连接。节目和“文本编辑”。
从这句话中我应该理解什么?
据说“初始化数据段”包含全局变量和静态变量,但我还读到const char* string = "hello world"
使字符串文字“hello world”存储在初始化的只读区域中初始化读写区域中的字符指针变量字符串。 char* string
是存储为只读区域还是读写区域?由于两者都写在这里,我有点困惑。
据我所知,堆栈包含局部变量。这是对的吗?
答案 0 :(得分: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(应用程序二进制接口)。
答案 1 :(得分:1)
文本段通常也称为“代码”(“text”往往是Unix / linux名称,其他OS不一定使用该名称)。
在某种意义上它是可共享的,如果你运行两个执行C编译器的进程,或者你在两个不同的窗口中打开文本编辑器,它们都共享相同的“文本”部分 - 因为它没有' t在代码运行期间发生变化(文本段中不允许自修改代码)。
初始化字符串值存储在“ro-data”或“text”中,具体取决于编译器。是的,它不可写。
如果string
是一个全局变量,它将以“初始化数据”结束,该数据将保存“{hello world”消息的地址,其值为string
。 const
部分指的是指针指向的内容是常量的事实,因此我们实际上可以在代码中稍后将指针更改为string = "foo bar";
。
实际上,堆栈用于局部变量,通常用于调用堆栈(代码在完成当前函数后返回的位置)。
答案 2 :(得分:1)
但是,程序内存映像的实际布局完全取决于操作系统,通常也取决于程序本身。然而,从概念上讲,我们可以想到two segments of memory for a running program
1.文本或代码段 - 包含已编译的程序代码
2.数据段 - 包含初始化和未初始化的数据(全局,静态和本地)。数据段可以进一步细分如下:
2.1初始化数据段
2.2未初始化的数据段
2.3堆栈段
2.4堆段
初始化数据段存储所有预先初始化的全局,静态,常量和外部变量(使用extern关键字声明)。
未初始化的数据段或.bss段存储所有未初始化的全局,静态和外部变量(使用extern关键字声明)。
堆栈段用于存储所有局部变量,用于将参数传递给函数以及函数调用结束后要执行的指令的返回地址。
堆段也是存储动态分配变量的RAM的一部分。
转到第一个问题 - 如果您知道函数指针,那么您就知道函数名称返回函数的地址(该函数的入口点)。这些指令在汇编中编码。指令集可能因架构而异。
文本或代码部分是可共享的 - 如果多个正在运行的进程属于同一程序,则不需要将公共编译代码单独加载到内存中。例如,如果您已经打开了两个.doc文档,那么它们将有两个进程,但是肯定会有两个进程使用一些公共代码。
希望这会有所帮助。
答案 3 :(得分:0)
堆栈段是存储局部变量的区域。通过说局部变量意味着所有那些在每个函数中声明的变量,包括C程序中的main()。
当我们调用任何函数时,会创建堆栈帧,当函数返回时,会破坏堆栈帧,包括该特定函数的所有局部变量。
堆栈帧包含一些数据,如返回地址,传递给它的参数,局部变量以及调用函数所需的任何其他信息。
“堆栈指针(SP)”通过每次推送和跟踪来跟踪堆栈。通过调整堆栈指针到下一个或上一个地址来弹出操作。
您可以参考此链接获取实用信息: - http://www.firmcodes.com/memory-layout-c-program-2/