1. 程式人生 > >Linux 可重定位檔案 ELF結構

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  |
[email protected]
@.....| 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。

    程式中的非靜態區域性變數即不在資料段也不在程式碼段,可能在堆疊段。

    至此,所有段都分析完了。本文參考程式設計師的自我修養