堆栈,BSS,DATA,TEXT

本文详细介绍了Linux下的目标文件(.o)构成,包括其包含的代码段、数据段、BSS段等及其功能。同时探讨了应用程序的组成,如代码段、数据段、BSS段、栈和堆的内存管理,以及静态和动态内存分配的区别和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、目标文件


首先目标文件的构成,Linux下就是.o 文件
编译器编译源码后生成的文件叫目标文件(Object File)。
目标文件和可执行文件一般采用同一种格式,这种存储格式为 ELF。

目前文件的内容至少有编译后的机器指令代码和数据,除了这些,目标文件中还包含了链接时所必须的一些信息,比如符号表、调试信息、字符串等。

般目标文件将这些信息按照不同的属性,以段(segment)的形式存储。

代码段(.text):源代码编译过后的机器指令。
数据段(.data):全局变量和局部静态变量被放在数据段。
只读数据段(.rodata):const 修饰的变量和其他字符串常量。
bss 段:为未初始化的符号,预留足够的空间。未初始化的变量在 bss 段。
其他段。
如下:


ELF文件头

ELF 文件开头是一个头文件,它描述的是整个文件的属性,

包括:文件的类型、目标硬件、目标操作系统等信息。


代码段;数据段;BSS段等


代码段

C 语言编译后的机器指令,都保存在代码段(.text)。
将代码段反汇编我们可以发现机器(汇编指令):


数据段
数据段(.data)保存的是哪些已经初始化(非零)的全局变量(静态变量和非静态变量)和局部静态变量。

只读数据段
只读数据段(.rodata),保存的是只读数据。一般是程序中 const 修饰的只读变量 和字符串常量(包括 printf 函数中的格式化字符串%d)。

BSS段
bss 段(.bss),用来记录所有未初始化的全局变量(或者零初始化)和局部静态变量大小总和,然后为其预留位置。

未初始化的全局变量(或者零初始化)和局部静态变量,因为都是 0,所以在.data 段开辟存储空间存储 0 是没有必要的。

二、应用程序的组成

2.1组成


在高级语言的角度我们将一个程序主要分为如下的段:
代码段
数据段 (变量常量等)
BSS 段(未初始化)

一个可执行程序至少包含:代码段 + 数据段 + BSS 段。也就是说在存储时(没有加载到内存运行),至少拥有三个部分,分别是代码段(text)、数据段(data)、和BSS 段

当应用程序运行时(运行态),此时需要另外两个域:堆和栈。正在运行的程序:代码段 + 数据段 + BSS 段 + 堆 + 栈。


2.2 内存管理


在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和 BSS 段的加载,并在内存中为这些段分配空间。栈也由操作系统管理,不需要程序员显示的管理;堆段需要程序员自己管理,显示的申请和释放。

动态分配

在运行时执行动态分配。需要程序员显示管理,通过 malloc 申请,并且需要手动 free 掉,否则会造成内存泄漏。

静态分配

在编译时就已经决定好了分配多少 Text+Data+Bss+Stack(静态分配)。

静态分配的内存在进程结束后由系统释放(Text+Data),Stack 堆上的数据则在退出函数后立即被销毁。

三、各段说明

3.1 栈

栈保存函数的局部变量(不包括 static 修饰的变量),参数以及返回值。是一种后进先出(LIFO)的数据结构。
在调用函数或过程后,系统会清除栈上保存的局部变量、函数调用信息及其他信息。
栈的另外一个重要特征是,它的地址空间 向下减少,即当栈上保存的数据越多,栈的地址越低。静态内存分配。
注意,由于栈的空间通常比较小,一般 linux 程序只有几 M,故局部变量,函数入参应该避免出现超大栈内存使用,比如超大结构体,数组等,避免出现 stack overflow。

3.2 堆

堆保存函数内部动态分配(malloc 或 new)的内存,是另外一种用来保存程序信息的数据结构。
堆是先进先出(FIFO)数据结构。堆的地址空间是向上增加,即当堆上保存的数据越多,堆的地址越高。动态内存分配。
注意:堆内存需要程序员手动管理内存,通常适用于较大的内存分配,如频繁的分配较小的内存,容易导致内存碎片化。

3.3 BSS


bss 是英文 Block by Symbol 的简称。通常用来存放程序中未初始化和初始化为 0的全局变量的一块内存区域,在程序载入时由内核清零。数据段属于静态内存分配

3.4 数据段


通常用来存放程序中已初始化的(非 0)全局变量和静态局部变量。数据段的起始位置由链接定位文件确认,大小在编译链接时自动分配。数据段属于静态内存分配

3.4 代码段


代码段在内存中被映射为只读。它是由编译器在编译链接时自动计算的。通常是用来存放程序执行的指令。代码段输入静态内存分配。


总结:

<think>好的,我现在需要回答用户关于.text、.data和.bss段区别的问题。首先,用户之前已经询问过LINK_SECTION_DATA_SDRAM,现在转向更基础的段区别,可能是在学习嵌入式系统或编译链接相关的知识。我需要确保回答准确且适合他们的理解水平。 首先,我得回忆这三个段的基本定义。.text段通常存放程序的可执行代码,比如函数和指令。这部分是只读的,因为代码在运行时不需要修改。然后是.data段,用于已初始化的全局变量和静态变量,这些变量在程序启动时就有明确的值,并且是可读写的。接着是.bss段,存放未初始化的全局和静态变量,这些变量在程序加载时会被初始化为零,以节省可执行文件的空间,因为它们不需要存储初始值的数据。 接下来,我需要考虑如何结构化回答。用户之前的回答有明确的层次结构,比如核心概念、技术作用等,可能希望类似的清晰结构。我可以分点说明每个段的定义、内容、存储位置、生命周期、示例等,然后比较它们的区别,最后总结应用场景。 还要注意用户提到的嵌入式系统背景,可能需要结合内存分配的实际例子,比如在链接脚本中的使用,或者变量如何被分配到不同的段。同时,需要确保用中文表达,避免专业术语的混淆,必要时给出代码示例,比如用__attribute__指定段,或者链接脚本的片段。 需要确认是否存在常见的误解,比如有人认为.bss段不占用磁盘空间,但实际上在加载时需要分配内存空间。同时,要说明为什么.bss段节省空间,因为不需要存储零值,只需记录大小即可。 可能还需要比较它们在可执行文件中的表现形式,比如.data段包含实际初始值的数据,而.bss段在文件中只有占位符。此外,说明这些段在程序启动时如何被处理,比如.data从ROM复制到RAM,.bss在运行时初始化为零。 最后,应用场景部分可以提到嵌入式系统中资源受限的情况下,合理分配变量到不同段的重要性,比如将大数组放在.bss避免增大可执行文件,或者将关键代码放在.text段保证只读属性。 需要检查是否有遗漏的关键点,比如生命周期、读写权限,以及是否提到静态变量和全局变量的区别。另外,是否需要提到其他段如.rodata堆栈,但用户的问题仅限于这三个,所以可能不需要扩展。 总结:结构分为定义、对比表格、应用场景,确保每个部分清晰,例子明确,语言简洁。避免技术错误,比如正确说明.bss在文件中的处理方式,以及运行时内存分配。</think>在程序的内存布局中,`.text`、`.data` 和 `.bss` 是三个核心段(Section),它们的区别体现在存储内容、内存分配方式和应用场景上。以下是详细解释: --- ### **1. 基础定义与对比** | **段名** | **存储内容** | **存储位置** | **生命周期** | **读写权限** | |------------|----------------------------------|--------------------|--------------------|--------------| | **.text** | 可执行代码(函数、指令) | 只读存储器(如Flash) | 程序整个运行周期 | 只读 | | **.data** | **已初始化**的全局/静态变量 | 读写存储器(如RAM) | 程序整个运行周期 | 可读写 | | **.bss** | **未初始化**的全局/静态变量 | 读写存储器(如RAM) | 程序整个运行周期 | 可读写 | --- ### **2. 详细说明** #### **(1) .text 段** - **内容**:编译后的机器指令(如函数代码)。 - **特点**: - 只读属性,防止程序意外修改代码。 - 在嵌入式系统中通常存储在Flash中,运行时直接从Flash执行或加载到RAM加速访问。 - **示例**: ```c void main() { /* 代码存储在.text段 */ } ``` #### **(2) .data 段** - **内容**:已初始化的全局变量、静态变量(包括初始值非零的变量)。 - **特点**: - 程序启动时需将初始值从Flash复制到RAM。 - 占用可执行文件空间(需存储初始值)。 - **示例**: ```c int global_var = 42; // 全局变量,存储在.data段 static int static_var = 10; // 静态变量,存储在.data段 ``` #### **(3) .bss 段** - **内容**:未初始化或初始化为零的全局/静态变量。 - **特点**: - **不占用可执行文件空间**(仅记录变量所需内存大小)。 - 程序启动时由系统自动初始化为零。 - **示例**: ```c int uninit_var; // 未初始化全局变量,存储在.bss段 static int zero_var = 0; // 初始化为零的静态变量,存储在.bss段 ``` --- ### **3. 内存分配对比** | **行为** | **.text** | **.data** | **.bss** | |------------------------|-----------|-----------------|-----------------| | **可执行文件是否存储** | 是(代码) | 是(初始值数据) | **否**(仅大小) | | **运行时内存来源** | Flash直接执行或加载到RAM | Flash → RAM 复制 | RAM直接清零分配 | --- ### **4. 应用场景** - **.text**:存放核心算法、中断服务程序(ISR)等关键代码。 - **.data**:存储配置参数、初始状态等需持久化的数据。 ```c const char* default_config = "high_performance"; // 若为常量,应存于.rodata(只读数据段) ``` - **.bss**:优化大型未初始化数组,减少可执行文件体积。 ```c uint8_t buffer[1024*1024]; // 1MB缓冲区(不占用文件空间) ``` --- ### **5. 验证方法** - **通过编译生成Map文件**: ```bash gcc -Wl,-Map=output.map main.c ``` - **Map文件片段示例**: ``` .text 0x08000000 0x200 main.o .data 0x20000000 0x40 data.o .bss 0x20000040 0x400 bss.o ``` --- ### **6. 扩展知识** - **未显式初始化的变量**:C语言规定未初始化的全局/静态变量默认值为零,因此归入`.bss`段。 - **与堆栈的区别**:`.data`和`.bss`是程序启动时分配的静态内存,而堆(Heap)和栈(Stack)是运行时动态分配的区域。 通过合理规划这三个段的使用,可以有效优化程序的内存占用和启动速度,尤其在资源受限的嵌入式系统中至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值