GCC編譯器原理(二)------編譯原理一:ELF文件(2)

4、 ELF 文件格式分析

  • ELF文件(目標文件)格式主要四種:
    • 可重定向文件:
      • 文件保存着代碼和適當的數據,用來和其餘的目標文件一塊兒來建立一個可執行文件或者是一個共享目標文件。(目標文件或者靜態庫文件,即linux一般後綴爲 .a 和 .o 的文件)
    • 可執行文件:
      • 文件保存着一個用來執行的程序。(例如bash,gcc等)
    • 共享目標文件:
      • 共享庫。文件保存着代碼和合適的數據,用來被下鏈接編輯器和動態連接器連接。(linux下後綴爲 .so 的文件。)
      • 執行文件的格式與上述兩種文件的格式之間的區別主要在於觀察的角度不一樣:一種稱爲鏈接視圖(Linking View),一種稱爲執行視圖(Execution View)
    • 核心轉儲文件(core dump):
      • 當進程意外終止時,系統能夠將該進程的地址空間的內容及終止時的一些其餘信息轉儲到核心轉儲文件

目標文件既要參與程序連接又要參與程序執行。 出於方便性和效率考慮, 目標文件格式提供了兩種並行視圖,分別反映了這些活動的不一樣需求。linux

  • ELF header:ELF 文件頭
    • 包含了描述整個文件的基本屬性,好比 ELF 文件版本、目標機器型號、程序入口地址等等
  • Program header table:程序表頭。若是存在的話,告訴系統如何建立進程映像。用來構造進程映像的目標文件必須具備程序頭部表,可重定位文件不須要這個表
  • Section or Segment:節或段
    • ELF 文件中包含的各個節,具體見後面章節。
  • Section header table:節頭表,可選
    • 每一個節區在表中都有一項,描述了 ELF 文件包含的全部節的信息,好比每一個節的節名、節的長度、在文件中的偏移、讀寫權限及段的其餘屬性
    • 用於連接的目標文件必須包含節區頭部表,其餘目標文件能夠有,也能夠沒有這個表。
  • String tables:字符串表
  • Symbol tables:符號表

注意:儘管圖中顯示的各個組成部分是有順序的,實際上除了 ELF 頭部表之外,其餘節區和段都沒有規定的順序。數組

4.1 ELF header:文件頭

文件的最開始幾個字節給出如何解釋文件的提示信息。 這些信息獨立於處理器, 也獨立於文件中的其他內容。bash

仍是對 hello.c 這段代碼進行分析,對編譯出來的 a.out 文件執行命令:readelf -h a.out數據結構

  • ELF 文件頭中的定義以下:
    • Magic:ELF 魔數
    • Class:文件機器字節長度
    • Data:數據存儲方式
    • Version:版本
    • OS/ABI:運行平臺
    • ABI Version:ABI版本
    • Type:ELF 文件類型
    • Machine:硬件平臺
    • Version:硬件平臺版本
    • Entry point address:入口地址
    • Start of program headers:程序頭入口和長度
    • Start of section headers:節頭的位置和長度
    • Flags:處理器標誌
    • Size of this header:ELF 文件頭的大小
    • Size of program headers:程序頭的大小
    • Number of program headers:程序頭的數量
    • Size of section headers:節的大小
    • Number of section headers:節的數量
    • Section header string table index:段表頭字符串表的位置

段由若干個節(Section)構成,節頭表對每個節的信息有相關描述。對可執行程序而言,節頭表是可選的。 ELF 頭部是一個關於本文件的路線圖(road map),從整體上描述文件的結構。下面是ELF頭部的數據結構:編輯器

  • /usr/include/elf.h
 1 typedef struct
 2 {
 3     unsigned char e_ident[EI_NIDENT];     /* 魔數和相關信息 */
 4     Elf32_Half    e_type;                 /* 目標文件類型 */
 5     Elf32_Half    e_machine;              /* 硬件體系 */
 6     Elf32_Word    e_version;              /* 目標文件版本 */
 7     Elf32_Addr    e_entry;                /* 程序進入點 */
 8     Elf32_Off     e_phoff;                /* 程序頭部偏移量 */
 9     Elf32_Off     e_shoff;                /* 節頭部偏移量 */
10     Elf32_Word    e_flags;                /* 處理器特定標誌 */
11     Elf32_Half    e_ehsize;               /* ELF頭部長度 */
12     Elf32_Half    e_phentsize;            /* 程序頭部中一個條目的長度 */
13     Elf32_Half    e_phnum;                /* 程序頭部條目個數  */
14     Elf32_Half    e_shentsize;            /* 節頭部中一個條目的長度 */
15     Elf32_Half    e_shnum;                /* 節頭部條目個數 */
16     Elf32_Half    e_shstrndx;             /* 節頭部字符表索引 */
17 } Elf32_Ehdr;
 
  • e_ident[EI_NIDENT]ELF魔數
    • e_ident標識索引以下:

  • 對應的信息是 Magic、Class、Data、Version、OS/ABI 和 ABI Version
  • e_ident[0] - e_ident[3] 包含了ELF文件的魔數,依次是0x7f、'E'、'L'、'F'。注意,任何一個ELF文件必須包含此魔數。
  • e_ident[4] 表示硬件系統的位數,1表明32位,2表明64位。
  • e_ident[5] 表示數據編碼方式(字節序),1表明小端排序(最大有意義的字節佔有最低的地址),2表明大端排序(最大有意義的字節佔有最高的地址)。
  • e_ident[6] 指定ELF文件的主版本號,通常爲1。
  • e_ident[7]到e_ident[14]是填充符,一般是0。ELF格式規範中定義這幾個字節是被忽略的,但其實是這幾個字節徹底能夠可被利用。
  • e_ident[7] 爲0x21,表示本文件已被感染;或者存放可執行代碼。
  • e_type:ELF 文件類型
    • ET_NONE:值爲0。未知目標文件格式
    • ET_REL:值爲 1。可重定位文件,通常爲 .o 文件
    • ET_EXEC:值爲2。可執行文件
    • ET_DYN:值爲 3。共享目標文件,通常爲 .so 文件
    • ET_CORE:值爲4。Core 文件(轉儲格式)
    • ET_LOPROC:值爲 0xff00。特定處理器文件
    • ET_HIPROC:值爲 0xffff。特定處理器文件
    • ET_LOPROC 和 ET_HIPROC 之間的取值用來標識與處理器相關的文件格式。
  • e_machine:ELF 文件的 CPU 平臺屬性。相關常量以 EM_ 開頭

名稱ide

取值函數

含義ui

EM_NONEthis

0編碼

未指定

EM_M32

1

AT&T WE 32100

EM_SPARC

2

SPARC

EM_386

3

Intel 80386

EM_68K

4

Motorola 68000

EM_88K

5

Motorola 88000

EM_860

7

Intel 80860

EM_MIPS

8

MIPS RS3000

其它值都是保留的。特定處理器的 ELF 名稱會使用機器名來進行區分。

  • e_version:目標文件版本,通常爲常數 1

名稱

取值

含義

EV_NONE

0

非法版本

EV_CURRENT

1

當前版本

  • e_entry:程序入口地址,規定 ELF 程序入口的虛擬地址,操做系統在加載完該程序後從這個地址開始執行進程的指令。可重定位文件通常沒有入口地址,則這個值爲 0
  • e_phoff:對應 Start of program headers。程序頭部表格( Program Header Table)的偏移量(按字節計算)。若是文件沒有程序頭部表格,能夠爲 0。
  • e_shoff:對應 Start of section headers。節區頭部表格( Section Header Table) 的偏移量(按字節計算)。 若是文件沒有節區頭部表格,能夠爲 0。
  • e_flags:ELF 標誌位,用來標識一些 ELF 文件平臺相關的屬性。相關常量的格式通常爲 EF_machine_flag,machine 爲平臺,flag 爲標誌
  • e_ehsize:ELF 文件頭自己的大小(以字節計算),對應 Size of this header
  • e_phentsize:對應 Size of program headers。程序頭部表格的表項大小(按字節計算)
  • e_phnum:對應 Number of program headers。程序頭部表格的表項數目。能夠爲 0。
  • e_shentsize:對應 Size of section headers,節區頭部表格的表項大小(按字節計算)。
  • e_shnum:對應 Number of section headers,節區頭部表格的表項數目。能夠爲 0。
  • e_shstrndx:節區頭部表格中與節區名稱字符串表相關的表項的索引。 若是文件沒有節區名稱字符串表,此參數能夠爲 SHN_UNDEF。

ELF 頭部中大多數字段都是對子頭部數據的描述,其意義相對比較簡單。值得注意的是某些病毒可能修改字段 e_entry(程序進入點)的值,以指向病毒代碼。

4.2 Program header table:程序頭表

緊接ELF頭部的是程序頭表。執行命令:readelf -l a.out

程序頭是一個結構數組,包含了 ELF 頭表中字段 e_phnum 定義的條目,此結構描述一個段或其餘系統準備執行該程序所須要的信息。

結構體位於:/usr/include/elf.h

 1 typedef struct {
 2     Elf32_Word  p_type;               /* 段類型 */
 3     Elf32_Off   p_offset;             /* 段位置相對於文件開始處的偏移量 */
 4     Elf32_Addr  p_vaddr;              /* 段在內存中的地址 */
 5     Elf32_Addr  p_paddr;              /* 段的物理地址 */
 6     Elf32_Word  p_filesz;             /* 段在文件中的長度 */
 7     Elf32_Word  p_memsz;              /* 段在內存中的長度 */
 8     Elf32_Word  p_flags;              /* 段的標記 */
 9     Elf32_Word  p_align;              /* 段在內存中對齊標記 */
10 } Elf32_Phdr;
 

對一個ELF可執行程序而言,一個基本的段是標記 p_type 爲 PT_INTERP 的段,它代表了運行此程序所須要的程序解釋器(/lib/ld-linux.so.2),實際上也就是動態鏈接器(dynamic linker)。

  • 最重要的段是標記 p_type 爲 PT_LOAD 的段,它代表了爲運行程序而須要加載到內存的數據。查看上面實際輸入,能夠看見有兩個可 LOAD 段,第一個爲只讀可執行(FLg 爲 R E ),第二個爲可讀可寫(Flg 爲 RW)。
    • 段一包含了文本節 .text ,注意到 ELF 文件頭部中程序進入點的值爲 0x400430,它會指向節.text在內存中的地址。
    • 段二包含了數據節 .data,此數據節中數據是可讀可寫的,相對的只讀數據節 .rodata 包含在段一中。

4.3 Section:節區

  • 節區中包含目標文件中的全部信息,除了: ELF 頭部、程序頭部表格、節區頭部表格。節區知足如下條件:
    • 目標文件中的每一個節區都有對應的節區頭部描述它, 反過來, 有節區頭部不意味着有節區。
    • 每一個節區佔用文件中一個連續字節區域(這個區域可能長度爲 0)。
    • 文件中的節區不能重疊,不容許一個字節存在於兩個節區中的狀況發生。
    • 目標文件中可能包含非活動空間( INACTIVE SPACE)。這些區域不屬於任何頭部和節區,其內容未指定。

不少節區中包含了程序和控制信息。 下面的表中給出了系統使用的節區, 以及它們的類型和屬性。

名稱

類型

屬性

含義

.bss

SHT_NOBITS

SHF_ALLOC +SHF_WRITE

包含將出如今程序的內存映像中的爲初始化數據。根據定義,當程序開始執行,系統將把這些數據初始化爲 0。 此節區不佔用文件空間。

.comment

SHT_PROGBITS

(無)

包含版本控制信息。

.data

SHT_PROGBITS

SHF_ALLOC + SHF_WRITE

這些節區包含初始化了的數據,將出如今程序的內存映像中。

.data1

SHT_PROGBITS

SHF_ALLOC + SHF_WRITE

.debug

SHT_PROGBITS

(無)

此節區包含用於符號調試的信息。

.dynamic

SHT_DYNAMIC

 

此節區包含動態連接信息。節區的屬性將包含 SHF_ALLOC 位。是否 SHF_WRITE 位被設置取決於處理器。

.dynstr

SHT_STRTAB

SHF_ALLOC

此節區包含用於動態連接的字符串,大多數狀況下這些字符串表明了與符號表項相關的名稱。

.dynsym

SHT_DYNSYM

SHF_ALLOC

此節區包含了動態連接符號表。

.fini

SHT_PROGBITS

SHF_ALLOC + SHF_EXECINSTR

此節區包含了可執行的指令,是進程終止代碼的一部分。程序正常退出時,系統將安排執行這裏的代碼。

.got

SHT_PROGBITS

 

此節區包含全局偏移表。

.hash

SHT_HASH

SHF_ALLOC

此節區包含了一個符號哈希表。

.init

SHT_PROGBITS

SHF_ALLOC + SHF_EXECINSTR

此節區包含了可執行指令,是進程初始化代碼的一部分。當程序開始執行時,系統要在開始調用主程序入口以前(一般指 C 語言的 main 函數)執行這些代碼。

.interp

SHT_PROGBITS

 

此節區包含程序解釋器的路徑名。若是程序包含一個可加載的段,段中包含此節區,那麼節區的屬性將包含 SHF_ALLOC 位,不然該位爲 0。

.line

SHT_PROGBITS

(無)

此節區包含符號調試的行號信息,其中描述了源程序與機器指令之間的對應關係。其內容是未定義的。

.note

SHT_NOTE

(無)

此節區中包含註釋信息,有獨立的格式。

.plt

SHT_PROGBITS

 

此節區包含過程連接表( procedure linkage table)。

.relname

SHT_REL

 

這些節區中包含了重定位信息。若是文件中包含可加載的段,段中有重定位內容,節區的屬性將包含 SHF_ALLOC 位,不然該位置 0。傳統上 name 根據重定位所適用的節區給定。 例如 .text 節區的重定位節區名字將是: .rel.text 或者 .rela.text。

.relaname

SHT_RELA

 

.rodata

SHT_PROGBITS

SHF_ALLOC

這些節區包含只讀數據, 這些數據一般參與進程映像的不可寫段。

.rodata1

SHT_PROGBITS

SHF_ALLOC

.shstrtab

SHT_STRTAB

 

此節區包含節區名稱。

.strtab

SHT_STRTAB

 

此節區包含字符串, 一般是表明與符號表項相關的名稱。若是文件擁有一個可加載的段,段中包含符號串表, 節區的屬性將包含 SHF_ALLOC 位,不然該位爲 0。

.symtab

SHT_SYMTAB

 

此節區包含一個符號表。若是文件中包含一個可加載的段,而且該段中包含符號表,那麼節區的屬性中包含SHF_ALLOC 位,不然該位置爲 0。

.text

SHT_PROGBITS

SHF_ALLOC + SHF_EXECINSTR

此節區包含程序的可執行指令。

  • 在分析這些節區的時候,須要注意以下事項:
    • 以"."開頭的節區名稱是系統保留的。 應用程序可使用沒有前綴的節區名稱, 以免與系統節區衝突。
    • 目標文件格式容許人們定義不在上述列表中的節區。
    • 目標文件中也能夠包含多個名字相同的節區。
    • 保留給處理器體系結構的節區名稱通常構成爲:處理器體系結構名稱簡寫 + 節區名稱。
    • 處理器名稱應該與 e_machine 中使用的名稱相同。例如 .FOO.psect 街區是由 FOO 體系結構定義的 psect 節區。
  • 另外,有些編譯器對如上節區進行了擴展, 這些已存在的擴展都使用約定俗成的名稱,如:.sdata、.tdesc、.sbss、.lit四、.lit八、.reginfo、.gptab、.liblist、.conflict 等等

4.4 Section header table:節區頭部表格

執行命令 readelf -S a.out 能夠查看到節表頭,這裏面保存了 ELF 文件中的各類各樣的節。節表是 ELF 文件中除了文件頭之外最重要的結構,它描述了 ELF 各個 節 的信息,好比每一個節的節名、節的長度、在文件中的偏移、讀寫權限及節的其餘屬性。即 ELF 文件的節結構就是由節表來決定的,編譯器、連接器和裝載器都是依靠節表來定位和訪問各個節的屬性的。節表在 ELF 文件中的位置由 ELF 文件頭的"e_shoff"成員決定。

 1 There are 31 section headers, starting at offset 0x19d8:
 2 
 3 Section Headers:
 4   [Nr] Name              Type        Address           Offset    Size              EntSize           Flags  Link  Info  Align
 5   [ 0]                   NULL        0000000000000000  00000000  0000000000000000  0000000000000000         0     0     0
 6   [ 1] .interp           PROGBITS    0000000000400238  00000238  000000000000001c  0000000000000000   A     0     0     1
 7   [ 2] .note.ABI-tag     NOTE        0000000000400254  00000254  0000000000000020  0000000000000000   A     0     0     4
 8   [ 3] .note.gnu.build-i NOTE        0000000000400274  00000274  0000000000000024  0000000000000000   A     0     0     4
 9   [ 4] .gnu.hash         GNU_HASH    0000000000400298  00000298  000000000000001c  0000000000000000   A     5     0     8
10   [ 5] .dynsym           DYNSYM      00000000004002b8  000002b8  0000000000000060  0000000000000018   A     6     1     8
11   [ 6] .dynstr           STRTAB      0000000000400318  00000318  000000000000003d  0000000000000000   A     0     0     1
12   [ 7] .gnu.version      VERSYM      0000000000400356  00000356  0000000000000008  0000000000000002   A     5     0     2
13   [ 8] .gnu.version_r    VERNEED     0000000000400360  00000360  0000000000000020  0000000000000000   A     6     1     8
14   [ 9] .rela.dyn         RELA        0000000000400380  00000380  0000000000000018  0000000000000018   A     5     0     8
15   [10] .rela.plt         RELA        0000000000400398  00000398  0000000000000030  0000000000000018  AI     5    24     8
16   [11] .init             PROGBITS    00000000004003c8  000003c8  000000000000001a  0000000000000000  AX     0     0     4
17   [12] .plt              PROGBITS    00000000004003f0  000003f0  0000000000000030  0000000000000010  AX     0     0     16
18   [13] .plt.got          PROGBITS    0000000000400420  00000420  0000000000000008  0000000000000000  AX     0     0     8
19   [14] .text             PROGBITS    0000000000400430  00000430  0000000000000192  0000000000000000  AX     0     0     16
20   [15] .fini             PROGBITS    00000000004005c4  000005c4  0000000000000009  0000000000000000  AX     0     0     4
21   [16] .rodata           PROGBITS    00000000004005d0  000005d0  0000000000000011  0000000000000000   A     0     0     4
22   [17] .eh_frame_hdr     PROGBITS    00000000004005e4  000005e4  0000000000000034  0000000000000000   A     0     0     4
23   [18] .eh_frame         PROGBITS    0000000000400618  00000618  00000000000000f4  0000000000000000   A     0     0     8
24   [19] .init_array       INIT_ARRAY  0000000000600e10  00000e10  0000000000000008  0000000000000000  WA     0     0     8
25   [20] .fini_array       FINI_ARRAY  0000000000600e18  00000e18  0000000000000008  0000000000000000  WA     0     0     8
26   [21] .jcr              PROGBITS    0000000000600e20  00000e20  0000000000000008  0000000000000000  WA     0     0     8
27   [22] .dynamic          DYNAMIC     0000000000600e28  00000e28  00000000000001d0  0000000000000010  WA     6     0     8
28   [23] .got              PROGBITS    0000000000600ff8  00000ff8  0000000000000008  0000000000000008  WA     0     0     8
29   [24] .got.plt          PROGBITS    0000000000601000  00001000  0000000000000028  0000000000000008  WA     0     0     8
30   [25] .data             PROGBITS    0000000000601028  00001028  0000000000000010  0000000000000000  WA     0     0     8
31   [26] .bss              NOBITS      0000000000601038  00001038  0000000000000008  0000000000000000  WA     0     0     1
32   [27] .comment          PROGBITS    0000000000000000  00001038  0000000000000035  0000000000000001  MS     0     0     1
33   [28] .shstrtab         STRTAB      0000000000000000  000018cc  000000000000010c  0000000000000000         0     0     1
34   [29] .symtab           SYMTAB      0000000000000000  00001070  0000000000000648  0000000000000018        30    47     8
35   [30] .strtab           STRTAB      0000000000000000  000016b8  0000000000000214  0000000000000000         0     0     1
36 Key to Flags:
37   W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
38   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
39   O (extra OS processing required) o (OS specific), p (processor specific)
 

除了使用 readelf 能夠查看節的詳細信息外,也可使用 objdump 來查看 ELF 文件中節,只不過 objdump 只列出 ELF 文件中關鍵的節,省略了其餘輔助節。以下:

ELF 頭部中, e_shoff 成員給出從文件頭到節區頭部表格的偏移字節數; e_shnum 給出表格中條目數目; e_shentsize 給出每一個項目的字節數。 從這些信息中能夠確切地定位節區的具體位置、長度。

節區頭部表格中比較特殊的幾個下標以下:

名稱

取值

說明

SHN_UNDEF

0

標記未定義的、缺失的、不相關的,或者沒有含義的節區引用

SHN_LORESERVE

OXFF00

保留索引的下界

SHN_LOPROC

0XFF00

 

SHN_HIPROC

0XFF1F

保留給處理器特殊的語義

SHN_ABS

OXFFF1

包含對應引用量的絕對取值。這些值不會被重定位所影響

SHN_COMMON

OXFFF2

相對於此節區定義的符號是公共符號。如 FORTRAN 中 COMMON 或者未分配的 C 外部變量。

SHN_HIRESERVE

0XFFFF

保留索引的上界

介於 SHN_LORESERVE 和 SHN_HIRESERVE 之間的表項不會出如今節區頭部表中。

節頭表結構體在 /usr/include/elf.h 中,結構以下:

 1 typedef struct elf32_shdr {
 2     ELF32_Word      sh_name;        /* 節名 */
 3     ELF32_Word      sh_type;        /* 節的類型 */
 4     ELF32_Word      sh_flags;       /* 節的標誌位 */
 5     ELF32_Addr      sh_addr;        /* 節的虛擬地址 */
 6     ELF32_Off       sh_offset;      /* 節偏移 */
 7     ELF32_Word      sh_size;        /* 節的長度 */
 8     ELF32_Word      sh_link;        /* 節鏈接信息 */
 9     ELF32_Word      sh_info;        /* 節鏈接信息 */
10     ELF32_Word      sh_addralign;   /* 節地址對齊 */
11     ELF32_Word      sh_entsize;     /* 項的長度 */
12 } ELF32_Shdr;
 
  • sh_name:節名。節名是個字符串,它位於一個叫作 ".shstrtab"的字符串表中。sh_name 是節名字符串在 ".shstrtab"中的偏移
  • sh_type:節的類型。節的名字只在編譯和連接的過程當中有意義,但它不能真正的表示節的類型。咱們能夠將一個數據段命名爲 ".text",對於編譯器和連接器來講,主要決定節的屬性是節的類型(sh_type)和節的標誌位(sh_flags)。節的類型相關常量以 SHT_ 開頭,以下:

名稱

取值

說明

SHT_NULL

0

此值標誌節區頭部是非活動的,沒有對應的節區。此節區頭部中的其餘成員取值無心義。

SHT_PROGBITS

1

此節區包含程序定義的信息,其格式和含義都由程序來解釋。

SHT_SYMTAB

2

此節區包含一個符號表。目前目標文件對每種類型的節區都只能包含一個,不過這個限制未來可能發生變化。通常, SHT_SYMTAB 節區提供用於連接編輯(指 ld 而言)的符號,儘管也可用來實現動態連接。

SHT_STRTAB

3

此節區包含字符串表。目標文件可能包含多個字符串表節區。

SHT_RELA

4

此節區包含重定位表項, 其中可能會有補齊內容( addend),例如 32 位目標文件中的 Elf32_Rela 類型。目標文件可能擁有多個重定位節區。

SHT_HASH

5

此節區包含符號哈希表。全部參與動態連接的目標都必須包含一個符號哈希表。目前,一個目標文件只能包含一個哈希表,不過此限制未來可能會解除。

SHT_DYNAMIC

6

此節區包含動態連接的信息。目前一個目標文件中只能包含一個動態節區,未來可能會取消這一限制。

SHT_NOTE

7

此節區包含以某種方式來標記文件的信息。

SHT_NOBITS

8

這種類型的節區不佔用文件中的空間,其餘方面和 SHT_PROGBITS 類似。 儘管此節區不包含任何字節, 成員 sh_offset 中仍是會包含概念性的文件偏移

SHT_REL

9

此節區包含重定位表項, 其中沒有補齊( addends),例如 32 位目標文件中的 Elf32_rel 類型。目標文件中能夠擁有多個重定位節區。

SHT_SHLIB

10

此節區被保留,不過其語義是未規定的。包含此類型節區的程序與 ABI 不兼容。

SHT_DYNSYM

11

做爲一個完整的符號表,它可能包含不少對動態連接而言沒必要要的符號。所以,目標文件也能夠包含一個 SHT_DYNSYM 節區,其中保存動態連接符號的一個最小集合,以節省空間。

SHT_LOPROC

0X70000000

這一段(包括兩個邊界),是保留給處理器專用語義的。

SHT_HIPROC

OX7FFFFFFF

SHT_LOUSER

0X80000000

此值給出保留給應用程序的索引下界。

SHT_HIUSER

0X8FFFFFFF

此值給出保留給應用程序的索引上界。

其它的節區類型是保留的。

  • sh_flags:節的標誌位。節的標誌位表示該節在進程虛擬地址空間中的屬性,好比是否可寫,是否可執行等。相關常量以 SHF_ 開頭:
    • SHF_WRITE:值爲1,表示該節在進程空間中可寫
    • SHF_ALLOC:值爲2,表示該節在進程空間中須要分配空間。有些包含指示或控制信息的節不須要在進程空間中被分配空間,它們通常不會有這個標誌。像代碼段、數據段和 .bss 段都會有這個標誌
    • SHF_EXECINSTR:值爲4,表示該節在進程空間中能夠被執行,通常指代碼節
    • SHF_MASKPROC:值爲 0xf000000,全部包含於此掩碼中的四位都用於處理器專用的語義。
  • sh_addr:節的虛擬地址。若是該節能夠被加載,則 sh_addr 爲該節被加載後在進程地址空間中的虛擬地址;不然 sh_addr 爲0
    • 系統保留段的屬性以下表

Name

sh_type

sh_flag

.bss

SHT_NOBITS

SHF_ALLOC + SHF_WRITE

.comment

SHT_PROGBITS

none

.data

SHT_PROGBITS

SHF_ALLOC + SHF_WRITE

.data1

SHT_PROGBITS

SHF_ALLOC + SHF_WRITE

.debug

SHT_PROGBITS

none

.dynamic

SHT_DYNAMIC

SHF_ALLOC + SHF_WRITE

在有些系統下 .dynamic 節多是隻讀的,因此沒有 SHF_WRITE 標誌位

.hash

SHT_HASH

SHF_ALLOC

.line

SHT_PROGBITS

none

.note

SHT_NOTE

none

.rodata

SHT_PROGBITS

SHF_ALLOC

.rodata1

SHT_PROGBITS

SHF_ALLOC

.shstrtab

SHT_STRTAB

none

.strtab

SHT_STRTAB

若是該 ELF 文件中有可裝載的段須要用到該字符串表,那麼該字符串表也將被裝載到進程空間,則有 SHF_ALLOC 標誌位

.symtab

SHT_SYMTAB

同字符串表

.text

SHT_PROGBITS

SHF_ALLOC

  • sh_offset:節偏移。若是該節存在於文件中,則表示該節在文件中的偏移;不然無心義。好比 sh_offset 對於 BSS 節來講就沒有意義。SHT_NOBITS 類型的節區不佔用文件的空間, 所以其 sh_offset 成員給出的是其概念性的偏移。
  • sh_size:此成員給出節區的長度(字節數)。除非節區的類型是 SHT_NOBITS,不然節區佔用文件中的 sh_size 字節。類型爲 SHT_NOBITS 的節區長度可能非零, 不過卻不佔用文件中的空間。
  • sh_link 和 sh_info:節鏈接信息。
    • sh_link 此成員給出節區頭部表索引連接。其具體的解釋依賴於節區類型。
    • sh_info 此成員給出附加信息,其解釋依賴於節區類型。
    • 若是節的類型是與連接相關的(不管是動態連接或靜態連接),好比重定位表、符號表等,那麼這兩個成員所包含的意義以下表所示。對於其餘類型的段,這兩個成員沒有意義。

sh_type

sh_link

sh_info

SHT_DYNAMIC

該節所用的字符串表在節表中的下標

0

SHT_HASH

該節所使用的符號表在節表中的下標

0

SHT_REL

該節所使用的相應符號表在節表中的下標

該重定位表所做用的節在節表中的下標

SHT_RELA

SHT_SYMTAB

操做系統相關的

操做系統相關的

SHT_DNYSYM

other

SHN_UNDEF

0

  • sh_addralign:節地址對齊。
    • 某些節區帶有地址對齊約束。例如,若是一個節區保存一個 doubleword, 那麼系統必須保證整個節區可以按雙字對齊。 sh_addr 對 sh_addralign 取模,結果必須爲 0。目前僅容許取值爲 0 和 2 的冪次數。數值 0 和 1 表示節區沒有對齊約束。
  • sh_entsize:項的長度。有些節包含了一些固定大小的項,好比符號表,它包含的每一個符號所佔的大小都是同樣的。對於這種節,sh_entsize 表示每一個項的大小。若是爲 0 ,則表示該節不包含固定大小的段。

索引爲零(SHN_UNDEF)的節區頭部也是存在的,儘管此索引標記的是未定義的節區引用。這個節區的內容固定以下(SHN_UNDEF(0)節區的內容):

字段名稱

取值

說明

sh_name

0

無名稱

sh_type

SHT_NULL

非活動

sh_flags

0

無標誌

sh_addr

0

無地址

sh_offset

0

無文件偏移

sh_size

0

無尺寸大小

sh_link

SHN_UNDEF

無連接信息

sh_info

0

無輔助信息

sh_addralign

0

無對齊要求

sh_entsize

0

無表項

當前的映射以下:

ELF 格式能夠比 COFF 格式包含更多的調試信息。在 I386 平臺 LINUX 系統下,用命令 file 查看一個 ELF 可執行程序的可能輸出是:a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped。

相關文章
相關標籤/搜索