可重定位目标文件解析

本文章旨在解析ELF文件类型中的可重定位文件,ELF类型还有剩余的两个可执行文件和共享目标文件日后更新
文章使用的例程如下,最简单的hello.c

#include <stdio.h>
int main()
{
         printf("hello, world\n");
         return 0;
}

首先我们先生成可重定位目标文件

gcc -c  hello.c

先放一个可重定位目标文件的结构的图
在这里插入图片描述接下来我们一一地来看一遍这些节都是什么

首先看一下ELF的文件大体的信息

在这里插入图片描述
选取几个解释一下

  1. Type: REL (Relocatable file) : 可以看出.o文件的类型为可重定位文件;
  2. Number of program headers: 0:可以看出可重定位文件的program header table的长度为0。因为在可重定位文件里不需要program header table;
  3. Entry point address:0x0同上,由于可重定位文件不能直接执行,因此其入口地址为0(默认值);
  4. Size of this header: 64: ELF文件头大小为64 byte。
  5. start of section headers:从ELF文件起始地址偏移672个字节处是section header table(节头表)的起始地址,section header table中共有13项,每项的大小为64 byte;

再看看ELF文件各部分,即看看各个section。

section的信息是由section header table描述的,我们可以通过以下命令查看section header table:
off为在目标文件中的偏移,flags代表运行时的访问权限align顾名思义时对齐方法,link和info用于储存和链接相关的节的信息,entsize指节中每个表项的长度,0为不固定

zzz@ubuntu:~/Desktop$ readelf -S hello.o
There are 13 section headers, starting at offset 0x2c8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000017  0000000000000000  AX       0     0     1
  [ 2] .rela.text        RELA             0000000000000000  00000218
       0000000000000030  0000000000000018   I      10     1     8
  [ 3] .data             PROGBITS         0000000000000000  00000057
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .bss              NOBITS           0000000000000000  00000057
       0000000000000000  0000000000000000  WA       0     0     1
  [ 5] .rodata           PROGBITS         0000000000000000  00000057
       000000000000000d  0000000000000000   A       0     0     1
  [ 6] .comment          PROGBITS         0000000000000000  00000064
       000000000000002c  0000000000000001  MS       0     0     1
  [ 7] .note.GNU-stack   PROGBITS         0000000000000000  00000090
       0000000000000000  0000000000000000           0     0     1
  [ 8] .eh_frame         PROGBITS         0000000000000000  00000090
       0000000000000038  0000000000000000   A       0     0     8
  [ 9] .rela.eh_frame    RELA             0000000000000000  00000248
       0000000000000018  0000000000000018   I      10     8     8
  [10] .symtab           SYMTAB           0000000000000000  000000c8
       0000000000000120  0000000000000018          11     9     8
  [11] .strtab           STRTAB           0000000000000000  000001e8
       0000000000000029  0000000000000000           0     0     1
  [12] .shstrtab         STRTAB           0000000000000000  00000260
       0000000000000061  0000000000000000           0     0     1

各个section的详细内容如下:

  • text段保存了可执行代码经过编译的机器代码
  • .data和.bss并没有占据任何空间,原因是代码中并未定义局部变量或者全局变量。实际上.data存放已初始化的全局和静态c变量 .bss存放未初始化的全局和静态c变量和初始化为0的全局和静态c变量;
  • .rodata:存放只读数据,在该程序中占据0xd个字节的空间,存放的就是我们的C代码中唯一的一个需要保存到.rodata段的字符串常量”hello, world”。这段还会存放switch的跳转表
  • .commont存放GCC版本信息;
  • .strtab指的是原C文件中的文件名和函数名等信息;
  • .shstrtab指的是section header string table,其中保存了各个section的名字;
  • .symtab保存了符号表,其中包括了.strtab里面定义的三个符号;什么是符号详见我的上一篇博客。除了包含.strtab外,符号表中还包含了一些section的符号表条目,这些条目给链接的时候需要和其他可重定位文件或者库的对应的section合并时提供了必要的信息。
    我们先解释一下什么是符号表再看结果,举个例子
    在这里插入图片描述
    在这里插入图片描述

在我们的hello.o中,其.symtab的内容如下:
ndx指示所在节索引数,即在那个节。其中UND为未定义,ABS为不用重定位。
bind:为本地/全局
type:有很多,节 文件 函数 等

 `zzz@ubuntu:~/Desktop$ readelf -s hello.o

Symbol table '.symtab' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     9: 0000000000000000    23 FUNC    GLOBAL DEFAULT    1 main
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts

文章末尾我们将可执行和可重定位略作对比,帮助我们更好更深地理解

在这里插入图片描述

发布了30 篇原创文章 · 获赞 5 · 访问量 6936

猜你喜欢

转载自blog.csdn.net/weixin_44735312/article/details/102056370