当前位置:   article > 正文

ELF目标文件分析

ELF目标文件分析

ELF目标文件分析

源代码

#include <stdio.h>

int printf( const char* format, ... );

int global_init_var = 84;
int global_unint_var;

void func1( int i )
{
    printf( "%d\n", i );
}

int main( void )
{
    static int static_var = 85;
    static int static_var2;

    int a = 1;
    int b;

    func1( static_var + static_var2 + a + b );

    return a;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

使用 GCC 编译这个文件:gcc -c SimpleSection.c

-c 参数表示只编译,不链接

查看段信息

使用 objdump -h SimpleSection.o 查看目标文件的结构和内容:

-h 把 ELF 文件的各个段的基本信息打印出来

在这里插入图片描述

使用ls -l SimpleSection.o可用看到文件的总大小位2080。

除了基本的代码段(.text)、数据段(.data)、BSS段(.bss)之外,还有只读数据段(.rodata)、注释信息段(.comment)和堆栈提示段(.note.GNU-stack)。

重要的属性:

  • Size 表示段的长度

  • File off 表示段所在的位置

  • 每个段的第2行中的 CONTENTS 表示该段在文件中存在,例如 .bss 段就没有,代表该ELF文件不存在该内容

结构如图所示:

在这里插入图片描述

使用size SimpleSection.o可以查看 ELF 文件的代码段,数据段和BSS段的长度:

text    data     bss     dec     hex filename
 219       8       4     231      e7 SimpleSection.o
  • 1
  • 2

dec表示3个段长度之和的十进制,hex表示长度和的16机制

代码段

使用命令:objdump -s -d SimpleSection.o

-s 将参数所有段的内容已16机制打印出来

-d将所有包含指令的段反汇编

在这里插入图片描述

如图所示,上半部分是ELF Header;下半部分是 .text 段,大小为0x5f,和前面吻合。

.text 段左边是偏移量,中间是 ASCII 码形式,右边是反汇编结果。

数据段和只读数据段

.data 段保存的是那些已经初始化了的全局静态变量和局部静态变量。源代码里面一共有两个这样的变量:global_init_var 和 static_var,两个变量刚好 8 字节,所以 .data 段的大小为 8 字节。

在函数 func1 中调用了 printf 时使用到了 “%d\n”,它是一种只读数据,所以他被放到了 .rodata段,其大小是 4 字节。这里我有一个疑惑就是为什么是4字节?我想的是这里有4个字符所以它是4字节,但是我把 \n 去掉以后它却是3字节。 .rodata 段存放的是只读数据,例如 const 变量,字符串常量

objdump -x -s -d SimpleSection.o

-x 显示全部信息

-s 将参数所有段的内容已16机制打印出来

-d将所有包含指令的段反汇编

在这里插入图片描述

.data 的前4个字节,从低到高是0x54、0x00、0x00、0x00。刚好是 global_init_var 的值84,而55000000则代表了 static_var 的值85。

这里还涉及到了大端和小段存放的问题,比如为什么不是00000054

BSS段

.bss 段存放的是未初始化的全局变量和局部静态变量。源代码中的 global_unint_var 和 static_var2 就是放在这里的。但是 .bss 段只有4字节,与8字节不符合。

通过符号表可以看到,只有 static_var2 被存放到了 .bss 段,global_unint_var 没有被放入任何段,只是一个未定义的 COMMON 符号。

这根不同的语言与不同的编译器实现有关,有些编译器会将未初始化的全局和局部静态变量全放入 .bss 段,有些则只预留一个未定义的全局变量符号,等到最终链接成可执行文件时再在 .bss 段分配空间。

Tips:

static int x1 = 0;
static int x2 = 1;
  • 1
  • 2

x1会被放在 .bss 段,因为它为0,可以被认为未初始化,因为未初始化的都是0,放在 .bss 段可以节省空间。

ps:

static int x1 = 0;
static int x2 = 1;
  • 1
  • 2

x1会被放在 .bss 段,因为它为0,可以被认为未初始化,因为未初始化的都是0,放在 .bss 段可以节省空间。

x2还是放在 .data 段。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/319434?site
推荐阅读
相关标签
  

闽ICP备14008679号