ELF文件数据布局探索(1)

作为一名Linux小白,第一次看到a.out这个名字,感觉实在是奇怪,搜了一下才知道这是编译器输出的默认可执行文件名

然后vi一下,哇,各种乱码,仔细看看,发现了三个清晰的字符ELF。继续搜索, 第一感觉就是这就是windows下的*.exe

顺便看到了readelf这条命令,就读了一下这个文件,发现这里边好多东西都不懂,后来在学习linux的过程中渐渐明白了

一部分,前几天刚好跟同学说到了关于ELF文件数据布局的问题,今天总结一下(罗嗦了这么多,真是不好意思)。



今天讨论的问题是:我们在源程序中定义的变量是否会被存储在ELF中以及存放在什么地方。让我们一步一步往下看:

先抛出两个结论:

a. data段的数据存储在ELF文件中;

b. bss段的数据不存储在ELF文件中,ELF文件中的bss段只是记录bss段所需要的大小。

1. 对比代码, 下面这段代码用于对比测试:

1 int main( ) {
2     return 0;
3 }

测试结果:

du -h a.out
8.0K    a.out

size a.out    text       data        bss        dec        hex    filename   1056        252          8       1316        524    a.out

2. 全局变量

2.1 未初始化:

1 int a[1024];
2 int main( ) {
3     return 0;
4 }

测试结果:

du -h a.out
8.0K    a.out
size a.out
   text       data        bss        dec        hex    filename
   1056        252       4128       5436       153c    a.out

可以看出,bss段的值变为了4128,正好是32 + 4096,为什么不是8 + 4096,我想应该是bss段是32字节对齐的,至于初始为什么没有对齐,留待大神解释。

那么为什么a.out的大小还是8.0K呢?大家先想一想。

2.2 初始化

1 int a[1024] = { 1 };
2 int main( ) {
3     return 0;
4 }

可能有同学要说了,你这只初始化了一个值吗?先往下看:

测试结果:

du -h a.out
12K    a.out
size a.out
   text       data        bss        dec        hex    filename
   1056       4372          8       5436       153c    a.out

这次bss段值没变,而数据段多了4372 - 252 = 4120,为什么不是4096,说明data段应该也是32字节对齐的。细心的同学肯定发现了,a.out的大小增加

了4K,这说明什么,说明a[1024]数据被写入了ELF文件中,也就是说data段中变量的值全部被写入到了ELF文件中。那现在想一想,为什么bss段增加了而a.out

没有增加呢,说明bss段只是记录了变量占据存储空间的大小,并没有在ELF中为变量分配存储,这里可以证明上面的两个结论是正确的。

现在回答一下上面的问题,为什么我只初始化了一个值,其实我们知道,数组是连续存放的,因此,只要初始化了一个值,其它的数据地址也就确定了。

3. 静态变量

3.1 未初始化

1 int main( ) {
2     static int a[1024];
3     return 0;
4 }

测试结果:

du -h a.out
8.0K    a.out
size a.out
   text       data        bss        dec        hex    filename
   1056        252       4128       5436       153c    a.out

bss段增加了4096 + 对齐字节,说明未经初始化的静态变量在bss段。

3.2 初始化

1 int main( ) {
2     static int a[1024] = { 1 };
3     return 0;
4 }

测试结果:

du -h a.out
12K    a.out
size a.out
   text       data        bss        dec        hex    filename
   1056       4372          8       5436       153c    a.out

data段增加了4096 + 对齐字节,目标文件a.out增加了4K,说明经过初始化的静态变量在data段。

4. 字符串常量

1 int main( ) {
2     char *p = "66";
3     return 0;
4 }

测试结果:

du -h a.out
7122    a.out
size a.out
   text       data        bss        dec        hex    filename
   1075        252          8       1345        541    a.out
1 int main( ) {
2     char *p = "666666666666";
3     return 0;
4 }

测试结果:

du -h a.out
8.0K    a.out
size a.out
   text       data        bss        dec        hex    filename
   1085        252          8       1345        541    a.out

可以看到只有text段增加了,而且通过设置不同的长度,第二次比第一增加了10B,说明“确实”是被放在text段了。但经过进一步分析,使用readelf命令,发现实际上

"666666666666"的地址在rodata段范围内,实际上字符串常量是被存储在rodata段中的,size命令看来也是个坑啊!需要指出,rodata段的内容也是要占据ELF文件

存储的,并不仅仅只记录数据大小。

5. 局部变量

这些变量不会存储在ELF中,只有装载ELF时,才会在内存中分配,下一篇文章我会讨论这个问题。

下表是我在Linux内核版本3.2.0的测试结果:

变量属性 是否在ELF中 是否存储在ELF中
未经初始化的全局变量 bss段
经过初始化的全局变量 data段
未经初始化的静态变量 bss段
经过初始化的静态变量 data段
字符串常量 rodata段
宏定义常量 rodata段
局部变量  

由于本人水平有限,文章中不当和错误之处不可避免,欢迎大家批评指正,愿共同进步!!!

时间: 2024-07-30 04:28:04

ELF文件数据布局探索(1)的相关文章

ELF文件

ELF文件格式是一个开发标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件 可执行文件 共享库 现在分析一下上一篇文章中经过汇编之后生成的目标文件max.o和链接之后生成的可执行文件max的格式,从而理解汇编.链接和加载执行的过程. 一.目标文件 ELF文件格式提供了两种不同的视角,在汇编器和链接器看来,ELF文件是由Section Header Table描述的一系列Section的集合,而执行一个ELF文件时,在加载器看来它是由Program Hea

探寻ELF文件内容,理清符号所在section

受<CSAPP>P453启发,想实际的看看ELF文件的内容,所以做了简单的尝试,希望不虚此行. 采用的程序demo是: swap.c extern int buf[]; int *bufp0 = &buf[0]; int *bufp1; void swap() { int temp; bufp1 = &buf[1]; temp = *bufp0; *bufp0 = *bufp1; *bufp1 = temp; } main.c #include <stdio.h>

ELF文件加载与动态链接(二)

GOT应该保存的是puts函数的绝对虚地址,这里为什么保存的却是[email protected]的第二条指令呢? 原来“解释器”将动态库载入内存后,并没有直接将函数地址更新到GOT表中,而是在函数第一次被调用时,才会进行函数地址的重定位,这样做的好处是可以加快程序加载速度,尤其对大型程序来说.有关这方面的更详细的信息,可以搜索“动态链接库的延迟绑定技术”. 继续看第二条指令,pushq $0x0代表什么? 查看Hello world程序的重定位节: [email protected]:~/wo

linux实践之ELF文件分析

linux实践之ELF文件分析 下面开始elf文件的分析. 我们首先编写一个简单的C代码. 编译链接生成可执行文件. 首先,查看scn15elf.o文件的详细信息. 以16进制形式查看scn15elf.o文件. 查看scn15elf.o中各个段和符号表的信息. 各个段的详细信息如下. 符号表的信息如下: 使用readelf命令查看各个段的详细信息: 段表信息如下: 符号表信息如下: 下面让我们开始分析文件头吧! 由于我的虚拟机是32位的,我下面就主要以32位的系统进行分析,就不比较32位机和64

实例分析ELF文件静态链接

1.ELF文件格式概貌 readelf -h 查看elf文件头部信息可以看到Type值有三种:REL,EXEC,DYN. REL文件是只被编译没有被链接过的文件,其格式属于左边一种,elf header+section1,2,3...+section header table,每个section对应一个section header table entry,section header table为各个section提供索引.没有被链接过的文件没有program header,不能被加载到内存中运

Android 存储文件方式之一---SharedPreferences 内容提供者,以xml 的方式进行数据 存储。是一种轻量级的文件数据存储

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 //UI界面的布局 文件<br><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"

实例分析ELF文件动态链接

参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台: [[email protected] dynamic_link]# uname -a Linux tanghuimin 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 实例讲解

ELF文件的格式和加载过程

http://blog.csdn.net/lingfong_cool/article/details/7832896 (一) ELF 文件的格式       ELF 文件类型 (1) 可重定位文件( .o 目标文件) : 用于链接创建可执行文件或 so 文件 (2) 可执行文件                     : 用于执行 (3)so( 共享对象 ) 文件            : 用于链接 注 :   一个 Program Header 对应一个 Segment 一个 Section

ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-04 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: 另一种是动态链接,是指库函数的代码并不进入应用软件的目标映像,应用软件在编译/链接阶段并