Linux 可重定位文件 ELF结构

    Linux下ELF文件类型分为以下几种:

    1、可重定位文件,例如SimpleSection.o;

    2、可执行文件,例如/bin/bash;

    3、共享目标文件,例如/lib/libc.so。


    再接下来的文章中,我们会使用objdump,readelf,hexdump,nm等来分析一个Linux中可重定位文件SimpleSection.o。


    首先附上SimpleSection.c源代码:

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


int global_init_var = 84;
int global_uninit_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;
}
    使用命令:

    gcc -c SimpleSection.c

    得到SimpleSection.o,下面我们首先附上SimpleSection.o的二进制内容以及整体轮廓。


    使用命令:

    hexdump -C SimpleSection.o,得到SimpleSection.o的二进制内容。

    计算机科学中,二进制0 1可以代表代码,字母,数字(十进制数和十六进制数)。

00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 3e 00 01 00 00 00  00 00 00 00 00 00 00 00  |..>.............|
00000020  00 00 00 00 00 00 00 00  88 01 00 00 00 00 00 00  |................|
00000030  00 00 00 00 40 00 00 00  00 00 40 00 0d 00 0a 00  |....@.....@.....|
00000040  55 48 89 e5 48 83 ec 10  89 7d fc 8b 45 fc 89 c6  |UH..H....}..E...|
00000050  bf 00 00 00 00 b8 00 00  00 00 e8 00 00 00 00 c9  |................|
00000060  c3 55 48 89 e5 48 83 ec  10 c7 45 f8 01 00 00 00  |.UH..H....E.....|
00000070  8b 15 00 00 00 00 8b 05  00 00 00 00 01 d0 03 45  |...............E|
00000080  f8 03 45 fc 89 c7 e8 00  00 00 00 8b 45 f8 c9 c3  |..E.........E...|
00000090  54 00 00 00 55 00 00 00  25 64 0a 00 00 47 43 43  |T...U...%d...GCC|
000000a0  3a 20 28 55 62 75 6e 74  75 2f 4c 69 6e 61 72 6f  |: (Ubuntu/Linaro|
000000b0  20 34 2e 36 2e 33 2d 31  75 62 75 6e 74 75 35 29  | 4.6.3-1ubuntu5)|
000000c0  20 34 2e 36 2e 33 00 00  14 00 00 00 00 00 00 00  | 4.6.3..........|
000000d0  01 7a 52 00 01 78 10 01  1b 0c 07 08 90 01 00 00  |.zR..x..........|
000000e0  1c 00 00 00 1c 00 00 00  00 00 00 00 21 00 00 00  |............!...|
000000f0  00 41 0e 10 86 02 43 0d  06 5c 0c 07 08 00 00 00  |.A....C..\......|
00000100  1c 00 00 00 3c 00 00 00  00 00 00 00 2f 00 00 00  |....<......./...|
00000110  00 41 0e 10 86 02 43 0d  06 6a 0c 07 08 00 00 00  |.A....C..j......|
00000120  00 2e 73 79 6d 74 61 62  00 2e 73 74 72 74 61 62  |..symtab..strtab|
00000130  00 2e 73 68 73 74 72 74  61 62 00 2e 72 65 6c 61  |..shstrtab..rela|
00000140  2e 74 65 78 74 00 2e 64  61 74 61 00 2e 62 73 73  |.text..data..bss|
00000150  00 2e 72 6f 64 61 74 61  00 2e 63 6f 6d 6d 65 6e  |..rodata..commen|
00000160  74 00 2e 6e 6f 74 65 2e  47 4e 55 2d 73 74 61 63  |t..note.GNU-stac|
00000170  6b 00 2e 72 65 6c 61 2e  65 68 5f 66 72 61 6d 65  |k..rela.eh_frame|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001c0  00 00 00 00 00 00 00 00  20 00 00 00 01 00 00 00  |........ .......|
000001d0  06 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001e0  40 00 00 00 00 00 00 00  50 00 00 00 00 00 00 00  |@.......P.......|
000001f0  00 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000200  00 00 00 00 00 00 00 00  1b 00 00 00 04 00 00 00  |................|
00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000220  b0 06 00 00 00 00 00 00  78 00 00 00 00 00 00 00  |........x.......|
00000230  0b 00 00 00 01 00 00 00  08 00 00 00 00 00 00 00  |................|
00000240  18 00 00 00 00 00 00 00  26 00 00 00 01 00 00 00  |........&.......|
00000250  03 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000260  90 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................|
00000270  00 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000280  00 00 00 00 00 00 00 00  2c 00 00 00 08 00 00 00  |........,.......|
00000290  03 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002a0  98 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
000002b0  00 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
000002c0  00 00 00 00 00 00 00 00  31 00 00 00 01 00 00 00  |........1.......|
000002d0  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002e0  98 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
000002f0  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000300  00 00 00 00 00 00 00 00  39 00 00 00 01 00 00 00  |........9.......|
00000310  30 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |0...............|
00000320  9c 00 00 00 00 00 00 00  2b 00 00 00 00 00 00 00  |........+.......|
00000330  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000340  01 00 00 00 00 00 00 00  42 00 00 00 01 00 00 00  |........B.......|
00000350  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000360  c7 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000370  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000380  00 00 00 00 00 00 00 00  57 00 00 00 01 00 00 00  |........W.......|
00000390  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003a0  c8 00 00 00 00 00 00 00  58 00 00 00 00 00 00 00  |........X.......|
000003b0  00 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................|
000003c0  00 00 00 00 00 00 00 00  52 00 00 00 04 00 00 00  |........R.......|
000003d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000003e0  28 07 00 00 00 00 00 00  30 00 00 00 00 00 00 00  |(.......0.......|
000003f0  0b 00 00 00 08 00 00 00  08 00 00 00 00 00 00 00  |................|
00000400  18 00 00 00 00 00 00 00  11 00 00 00 03 00 00 00  |................|
00000410  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000420  20 01 00 00 00 00 00 00  61 00 00 00 00 00 00 00  | .......a.......|
00000430  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000440  00 00 00 00 00 00 00 00  01 00 00 00 02 00 00 00  |................|
00000450  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000460  c8 04 00 00 00 00 00 00  80 01 00 00 00 00 00 00  |................|
00000470  0c 00 00 00 0b 00 00 00  08 00 00 00 00 00 00 00  |................|
00000480  18 00 00 00 00 00 00 00  09 00 00 00 03 00 00 00  |................|
00000490  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000004a0  48 06 00 00 00 00 00 00  66 00 00 00 00 00 00 00  |H.......f.......|
000004b0  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
000004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000004e0  01 00 00 00 04 00 f1 ff  00 00 00 00 00 00 00 00  |................|
000004f0  00 00 00 00 00 00 00 00  00 00 00 00 03 00 01 00  |................|
00000500  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000510  00 00 00 00 03 00 03 00  00 00 00 00 00 00 00 00  |................|
00000520  00 00 00 00 00 00 00 00  00 00 00 00 03 00 04 00  |................|
00000530  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000540  00 00 00 00 03 00 05 00  00 00 00 00 00 00 00 00  |................|
00000550  00 00 00 00 00 00 00 00  11 00 00 00 01 00 03 00  |................|
00000560  04 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000570  21 00 00 00 01 00 04 00  00 00 00 00 00 00 00 00  |!...............|
00000580  04 00 00 00 00 00 00 00  00 00 00 00 03 00 07 00  |................|
00000590  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000005a0  00 00 00 00 03 00 08 00  00 00 00 00 00 00 00 00  |................|
000005b0  00 00 00 00 00 00 00 00  00 00 00 00 03 00 06 00  |................|
000005c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000005d0  32 00 00 00 11 00 03 00  00 00 00 00 00 00 00 00  |2...............|
000005e0  04 00 00 00 00 00 00 00  42 00 00 00 11 00 f2 ff  |........B.......|
000005f0  04 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000600  54 00 00 00 12 00 01 00  00 00 00 00 00 00 00 00  |T...............|
00000610  21 00 00 00 00 00 00 00  5a 00 00 00 10 00 00 00  |!.......Z.......|
00000620  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000630  61 00 00 00 12 00 01 00  21 00 00 00 00 00 00 00  |a.......!.......|
00000640  2f 00 00 00 00 00 00 00  00 53 69 6d 70 6c 65 53  |/........SimpleS|
00000650  65 63 74 69 6f 6e 2e 63  00 73 74 61 74 69 63 5f  |ection.c.static_|
00000660  76 61 72 2e 31 35 39 34  00 73 74 61 74 69 63 5f  |var.1594.static_|
00000670  76 61 72 32 2e 31 35 39  35 00 67 6c 6f 62 61 6c  |var2.1595.global|
00000680  5f 69 6e 69 74 5f 76 61  72 00 67 6c 6f 62 61 6c  |_init_var.global|
00000690  5f 75 6e 69 6e 69 74 5f  76 61 72 00 66 75 6e 63  |_uninit_var.func|
000006a0  31 00 70 72 69 6e 74 66  00 6d 61 69 6e 00 00 00  |1.printf.main...|
000006b0  11 00 00 00 00 00 00 00  0a 00 00 00 05 00 00 00  |................|
000006c0  00 00 00 00 00 00 00 00  1b 00 00 00 00 00 00 00  |................|
000006d0  02 00 00 00 0e 00 00 00  fc ff ff ff ff ff ff ff  |................|
000006e0  32 00 00 00 00 00 00 00  02 00 00 00 03 00 00 00  |2...............|
000006f0  00 00 00 00 00 00 00 00  38 00 00 00 00 00 00 00  |........8.......|
00000700  02 00 00 00 04 00 00 00  fc ff ff ff ff ff ff ff  |................|
00000710  47 00 00 00 00 00 00 00  02 00 00 00 0d 00 00 00  |G...............|
00000720  fc ff ff ff ff ff ff ff  20 00 00 00 00 00 00 00  |........ .......|
00000730  02 00 00 00 02 00 00 00  00 00 00 00 00 00 00 00  |................|
00000740  40 00 00 00 00 00 00 00  02 00 00 00 02 00 00 00  |@...............|
00000750  21 00 00 00 00 00 00 00                           |!.......|

                                 图1


    使用命令ls -l SimpleSection.o,可以得到文件大小为1880字节,上面二进制内容正好也是1880个字节(0x758转换为十机制为1880)。


    SimpleSection.o的整体轮廓图如下,可能读者会想为什么会得到这样一张图,随着我们深入分析每个段的内容,答案自然会揭晓。

                                                                     图 2


    我们看到0x758是所有段结束的位置,换算成十进制就是1880个字节。和我们刚才获取的文件大小一样。

   

    下面我们来利用命令来分析ELF文件结构的每个部分:

    1、ELF Header

    使用命令readelf -h SimpleSection.o,得到下图。


                             图 3

    ELF文件头结构及相关参数被定义在“/usr/include/elf.h”中,如下:

typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf32_Half    e_type;                 /* Object file type */
  Elf32_Half    e_machine;              /* Architecture */
  Elf32_Word    e_version;              /* Object file version */
  Elf32_Addr    e_entry;                /* Entry point virtual address */
  Elf32_Off     e_phoff;                /* Program header table file offset */
  Elf32_Off     e_shoff;                /* Section header table file offset */
  Elf32_Word    e_flags;                /* Processor-specific flags */
  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
  Elf32_Half    e_phentsize;            /* Program header table entry size */
  Elf32_Half    e_phnum;                /* Program header table entry count */
  Elf32_Half    e_shentsize;            /* Section header table entry size */
  Elf32_Half    e_shnum;                /* Section header table entry count */
  Elf32_Half    e_shstrndx;             /* Section header string table index */
} Elf32_Ehdr;
    Type:ELF文件类型,本例中为REL(Relocatable File),可重定位文件。

    Start of section headers,段表在文件中偏移,就是图2中Section Table的位置为392(0x188)。

    Size of section headers,ELF文件头的大小为64个字节。

    Number of section headers,ELF拥有多少个断,本例为13个段。见图 7。

    Section header string table index,段表字符串表所在的段在段表中的下标。本例中等于10,见图 7。


    2、.text

    使用命令:

    objdump -d SimpleSection.o,得到了下图,由于是代码段,所以二进制代表汇编代码。


                            图 4     

 

    3、.data

    使用命令objdump -s SimpleSection.o,得到数据段,如下图:


                       图 5


    本例中存入数据段的是

int global_init_var = 84;
static int static_var = 85;
    共8个字节,一个是0x00000054,十进制是84;一个是0x0000000056,十进制是85。     


    4、.bss

    使用命令objdump -h SimpleSection.o,得到下图:


                      图 6

    本例中存入数据段的是

static int static_var2;
    大家会注意到int global_uninit_var;既没有在.data段中,也没有在.bss段中。如果在前面加上static,那么则存在.bss段中。


    5、.rodata

    .rodata存放的只读数据。25640a00,查看ASCII表代表的就是%d\n。


    6、.shstrtab(段表字符串表)

    如图1,存放的是

    ..symtab..strtab..shstrtab..rela.text..data..bs..rodata..comment..note.GNU-stak..rela.eh_frame


    7、.strtab(字符串表)

    如图1,存放的是

    SimpleSection.c.static_var.1594.static_var2.1595.global_init_var.global_uninit_var.func1.printf.main


    8、Section Table

    使用命令,readelf -S SimpleSection.o,得到下图:


                           图 7

    这就解释了图1,为什么要那么画。

    Offset表示段偏移,Size表示段大小。

    Type,PROGBITS表示段,NOBITS表示不占空间,.RELA表示重定位段,STRTAB表示字符串表,SYMTAB表示符号表。

    EntSize表示如果段中有重复的内容,则表示重复内容大小。比如下面要介绍的符号表就是重复内容组成的。

    在TYPE为RELA时,Link表示该段所使用的相应符号表在段表中,本例中为11。Info表示该重定位表所作用的段在段表中的下标。.rela.text为1,.rela.eh_frame为8。    


    9、.symtab(符号表)

    使用命令,readelf -s SimpleSection.o,得到下图:


                              图 8

    Name,表示字符串在字符串表中的下标;


    Ndx,SimpleSection.c为ABS,global_uninit_var为COM,表示这个变量是强引用或者弱引用,目前即不在.data段中,也不在.bss段中,等待链接时会确定。

    printf为UND,表示没有定义,即引用了外部的函数。

    global_init_var,NDX为3,表示在.data中,其余类似。表示符号所在的段在段表中的下标;参考图 7。


    Bind GLOBAL表示可以被外部引用或者引用外部的函数和变量。

    TYPE为OBJECT表示对象,FUNC表示函数,SECTION表示段,FILE表示文件,printf为NOTYPE,表示没有定义,是引用外部函数。

    SIZE表示大小。

    Value表示在本段中的偏移,比如static_var.1594表示在.data段中的偏移为4。 main在.data段中的偏移为21。


    最后介绍个命令,nm SimpleSection.o,结果如下:


    可以看出示所有可以被外部引用或者引用外部的函数和变量。

    T表示text;D和d表示data;b表示bss,C表示Common,U表示Undef。

    程序中的非静态局部变量即不在数据段也不在代码段,可能在堆栈段。


    至此,所有段都分析完了。本文参考程序员的自我修养。

你可能感兴趣的:(Linux开发之路)