zoukankan      html  css  js  c++  java
  • 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段
    局部变量  

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

  • 相关阅读:
    Hdu 1257 最少拦截系统
    Hdu 1404 Digital Deletions
    Hdu 1079 Calendar Game
    Hdu 1158 Employment Planning(DP)
    Hdu 1116 Play on Words
    Hdu 1258 Sum It Up
    Hdu 1175 连连看(DFS)
    Hdu 3635 Dragon Balls (并查集)
    Hdu 1829 A Bug's Life
    Hdu 1181 变形课
  • 原文地址:https://www.cnblogs.com/zhuoyuan/p/4128079.html
Copyright © 2011-2022 走看看