Linux下可执行程序的分段

简介: Linux下可执行程序的分段

Linux下可执行程序的分段


说明:

Linux系统下编译产生的二进制程序是以ELF格式存储的,ELF格式是分段的;Linux系统采用段式内存管理架构,二进制程序加载进内存后内存分布也是分段的。

windows系统也是类似的。

个人理解:

分段是由编译器和操作系统实现,编译时编译器将不同类型的元素存储到相应的段,以区分处理,利于管理和加快操作效率。

分段行为不是固定的,不同编译器,不同平台可能有细微差别,虚拟内存和硬盘都是连续的。

程序由数据和处理两部分组成,处理部分(代码)编译后为二进制指令(代码段)比较固定,而数据部分(变量)有多种形式,例如:全局变量,局部变量,static变量,const变量等等,为了实现这些需求和加快操作效率,因此数据段有多种分段类型。

一、代码:

段名:代码段(text段)

编译后生成给CPU执行的机器指令,一个程序只有一个代码段,只读,防止程序由于意外事故而修改自身指令。

该段也有可能包含一些只读的常量,例如字符串常量,const修饰的变量(各种单片机的编译器会这样存储),由编译器决定。

变量:

全局变量(生命周期等于整个程序执行期)

全局变量在编码时已经固定了,占用内存大小和值已确定,因为这些特性,全局变量可以在编译时就准备好,不需要等到运行时再去逐个分配内存设置值。

这里说的全局变量包括 全局变量,static的全局变量,static的局部变量。

全局变量由于初始值的不同,有以下两种情况。

二、已赋不为0的初始值:

段名:已初始化数据段(data段)。

初值不为0,编译器简单处理认为数据都不同,需要逐个变量保存到二进制程序文件中,程序运行时直接将整段数据拷贝进内存。

个人理解:编译器可以进一步优化,相同的值可以只存一份。

该段保存了程序中所有赋了初值并且初值不为0的全局变量,包括全局变量,static的全局变量,static的局部变量。

如果该段数据较多,会导致程序二进制文件非常大,如下:

int ar[300000] = {1};        //将全部存储在data段,虽然值都是一样的
static int a = 10;           //保存在data段
void test(){
    static int b = 10; 
}

三、未赋初值或者初值为0:

   1、段名:未初始化数据段(bss段)。

   2、由于可以将这些变量的初值处理成一样的,都设置为0,二进制程序文件就没必要存储这些值,只需要记录该段的首地址和段长度,程序运行加载进内存时再按这些参数申请和格式化内存就好。

   3、该段保存程序中没有进行初始化或者初始化为0的全局变量;例如:

int a; 
int b = 0;
static int a;
static int a = 0;
void test(){
    static int b;
    static int b = 0;
}

四、局部变量(生命周期由系统控制)

   1、段名:栈。

   2、由于局部变量不是固定的,无法在编译时进行处理。

   3、 增长方向:自顶向下增长;普通的局部变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。

   4、栈变量最大的特征是:栈变量都应该是临时变量,出栈后内存就非常可能被覆盖。

五、动态变量(生命周期由程序员控制)

  1、段名:堆。

  2、该段的大小并不固定,可动态扩张或缩减。

  3、因为动态变量并不是固定的,无法在编译时进行处理。

  4、动态存储区,是向高地址扩展的数据类型,是自下向上的扩展方式,动态内存分配的内存区域。

  5、堆变量最大的特征是:大内存变量或者永久变量,临时小内存变量不应该放在堆内存中,应该放在栈内存中。

六、只读变量

 1、段名:只读变量区域(rodata段)

 2、只读的内存区域,const修饰的常量,以及常量字符串保存在该区域。例如:

const int a = 100; 
char *b = "hello world"。 //hello world保存在该段,但是变量b不是。

存储时形态:

   二进制程序中不包含堆,栈需要动态管理的段,程序加载进内存才会产生。

运行时形态:

  1、每个进程都独自拥有4GB的虚拟内存空间,使用时再由系统转换成物理内存地址,该转换对用户是透明不可见的,因此时常讲的内存空间都是虚拟内存空间。

  2、程序的代码段和一些全局变量是固定的,不会改变的,编译时会将代码段和这些变量的虚拟内存地址确定,因此每次运行都是固定的。

  3、Linux下C程序的内存分布图如下,C程序将内存分为以下5部分,地址从低到高排列:

相关文章
|
1天前
|
存储 移动开发 Linux
Linux系统之部署h5ai目录列表程序
【5月更文挑战第3天】Linux系统之部署h5ai目录列表程序
23 1
|
1天前
|
Web App开发 存储 Linux
Linux(33)Rockchip RK3568 Ubuntu22.04上通过SSH运行Qt程序和关闭Chrome的密钥提示
Linux(33)Rockchip RK3568 Ubuntu22.04上通过SSH运行Qt程序和关闭Chrome的密钥提示
63 0
|
1天前
|
Linux 开发工具 C语言
Linux 安装 gcc 编译运行 C程序
Linux 安装 gcc 编译运行 C程序
34 0
|
1天前
|
Linux 应用服务中间件 网络安全
linux ssl 证书 --本地制作数字证书并进行程序的数字签名
linux ssl 证书 --本地制作数字证书并进行程序的数字签名
21 0
|
1天前
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
14 0
|
1天前
|
存储 Linux 编译器
【Linux】详解动态库链接和加载&&对可执行程序底层的理解
【Linux】详解动态库链接和加载&&对可执行程序底层的理解
|
1天前
|
Linux C++
【Linux】详解进程程序替换
【Linux】详解进程程序替换
|
1天前
|
网络协议 Java Linux
【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)
【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)
14 0
|
1天前
|
存储 网络协议 算法
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
15 0