ELF 文件格式

---以hello world程式爲例分析ELF頭部格式
icymoon@NKU
0 幾個概念
ELF:      Executable and Linking Format
ELF的三種類型《出自EXECUTABLE AND LINKABLE FORMAT (ELF)》:
* 一個可重定位(relocatable)文件保存着代碼和適當的數據,用來和其他的
  object文件一起來創建一個可執行文件或是個共享文件。
* 一個可執行(executable)文件保存着一個用來執行的程式;該文件指出了
  exec(BA_OS)怎麼來創建程式進程映象。
* 一個共享object文件保存着代碼和合適的數據,用來被下面的兩個鏈接器
  鏈接。第一個是連接編輯器[請參看ld(SD_CMD)],能和其他的可重定位和
  共享object文件來創建其他的object。第二個是動態鏈接器,聯合一個
  可執行文件和其他的共享object文件來創建一個進程映象。
  目標文件格式如下:
Linking 視角 Execution 視角
============ ==============
ELF header ELF header
Program header table (optional) Program header table
Section 1 Segment 1
... Segment 2
Section n ...
Section header table Section header table (optional)

1 環境
Arch: Intel 32
       OS: Redhat 9.0
       Compiler: gcc, icc
       Other Tools: UltraEdit, readelf, objdump…

2. 程式源碼及編譯
常見的Hello World,源碼如下
#include
int main(void)
{
    printf("Hello World!\n");
    return 0;
}
可能用到的編譯命令:
$ gcc -o hello.gcc hello.c
$ gcc -static -o hello.gcc.static hello.c
$ gcc -shared -o hello.gcc.shared hello.c
$ icc -o hello.icc.o -c hello.c
生成的文件包括: hello.gcc,hello.gcc.static,hello.gcc.shared,hello.icc.o

3. ELF頭部格式
3.1 ELF頭部數據結構表示:
#define EI_NIDENT       16
typedef struct {
      unsigned char       e_ident[EI_NIDENT];
      Elf32_Half          e_type;
      Elf32_Half          e_machine;
      Elf32_Word          e_version;
      Elf32_Addr          e_entry;
      Elf32_Off           e_phoff;
      Elf32_Off           e_shoff;
      Elf32_Word          e_flags;
      Elf32_Half          e_ehsize;
      Elf32_Half          e_phentsize;
      Elf32_Half          e_phnum;
      Elf32_Half          e_shentsize;
      Elf32_Half          e_shnum;
      Elf32_Half          e_shstrndx;
  } Elf32_Ehdr;
其中,數據類型大小如下:
  Name           Size  Alignment   Purpose
  ====           ==== =========   =======
  Elf32_Addr      4       4           Unsigned program address
  Elf32_Half      2       2       Unsigned medium integer
  Elf32_Off       4       4       Unsigned file offset
  Elf32_Sword     4       4       Signed large integer
  Elf32_Word      4       4       Unsigned large integer
  unsigned char   1       1       Unsigned small integer
3.2 以hello world程式爲例,看看到底是什麼樣子的
7E 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00
02 00 03 00 01 00 00 00 78 82 04 08 34 00 00 00
3C 1D 00 00 00 00 00 00 34 00 20 00 06 00 28 00
22 00 1F 00
前16個字節是屬於unsigned char       e_ident[EI_NIDENT],標識ELF的一些信息。
00000000-00000003 :7E 45 4C 46
       ELF文件以一個magic number開頭(7F),接下來是’E’,’L’,’F’這三個字符。
00000004:01
       這位是標明文件的類型,如果是0爲非法,1爲32位目標,2爲64位目標,當初屬於預留的,呵呵。在這裏爲32位目標文件。
00000005:01
       這位是處理器的編碼方式,01表示高位在前,02表示低位在前,0是非法數據編碼。
00000006:01
       這位是頭部版本號。
00000007-0000000f:00 00 00 00 00 00 00 00 00
       標記 e_ident 中未使用字節的開始。初始化爲 0。

       然後是e_type,用來指明文件類型是三種object文件中的哪種
00000010-00000011:02 00
       這裏,2代表可執行文件,1是可重定位的目標文件(gcc ?c得到的是這樣的文件),而3表示共享目標文件(gcc ?shared得到的文件如此),同樣,0是指未知的目標文件。其他的值含義如下
        ET_CORE         4  Core file
        ET_LOPROC  0xff00  Processor-specific
        ET_HIPROC  0xffff  Processor-specific

       下面是e_machine,用以指定系統的體系結構
00000012-00000013:03 00
       這裏的3是指Intel 80386結構,據某篇文件說,ia32的結構上這位是必須指定爲EM_386的,即值爲3。其他取值含義如下:0是未指定,1是EM_M32,即 AT&TWE 32100,2是EM_SPARC,即SPARC結構,4和5分別指EM_68K(Motorola 68000)和EM_88K(Motorola 88000),7指EM_860(Intel 80860),8指EM_MIPS(MPIS RS3000)。

       第14到17位是e_version,指明目標文件版本
00000014-00000017:01 00 00 00
       取1爲當前版本EV_CURRENT,取0爲非法版本EV_NONE

       接下來是e_entry,程式入口的虛擬地址。如果目標文件沒有程式入口,能爲 0
00000018-0000001b:78 82 04 08

    然後是e_phoff和e_shoff,指程式頭部表格和節區表格的偏移量, 以字節計算,如果沒有的話,能爲0。這裏是這樣的
0000001c-00000023:34 00 00 00 3C 1D 00 00
      
       後面接e_flags,是和文件和處理器相關的標誌。這裏是
00000024-00000027:00 00 00 00,不明白這裏都是0是什麼意思。

       然後就是e_ehsize了,說明了ELF頭部的大小(字節)
00000028-00000029:34 00

       剩下的是e_phentsize,e_phnum,和e_shentsize,e_shnum,表明程式頭部表格的表項大小和項目數和節區頭部表格的表項大小和數目,每個2字節長。
0000002a-00000031:20 00 06 00 28 00 22 00
       最後是節區頭部表格中和名稱字串相關的表項索引。如果沒有節區名稱字符串表,此參數可爲SHN_UNDEF
00000032-00000033:1F 00

       到此,就是個簡單的hello world程式通過gcc ?o hello hello.c編譯得到的文件的ELF頭部格式。

4 犯的錯誤
       沒有注意到字節序,數錯了位,在e_machine那裏徘徊了非常久,以爲體系結構被填充爲0,即未知,然後嘗試用icc編譯,結果還是那樣,結果在UE中改了那個byte的值,程式無法運行,才發現這只是粗心的問題。

5. 參考
ELF格式
《深入理解計算機系統》

 

============================================================

這篇文檔是爲那些想創建目標文件或者在不同的操作系統上執行文件的開發
着準備的。它分以下三個部分:

* 第一部分, “目標文件Object Files”描述了ELF目標文件格式三種主要
  的類型。
* 第二部分, “程序轉載和動態連接”描述了目標文件的信息和系統在創建
  運行時程序的行爲。
* 第三部分, “C 語言庫”列出了所有包含在libsys中的符號,標準的ANSI C
  和libc的運行程序,還有libc運行程序所需的全局的數據符號。

 

 ________________________________________________________________


   1. 目標文件(Object file)

   ________________________________________________________________


   ========================= 序言 =========================


第一部分描述了iABI的object文件的格式, 被稱爲ELF(Executable
and Linking Format). 在object文件中有三種主要的類型。

* 一個可重定位(relocatable)文件保存着代碼和適當的數據 ,用來和其他的
  object文件一起來創建一個可執行文件或者是一個共享文件。
* 一個可執行(executable)文件 保存着一個用來執行的程序;該文件指出了
  exec(BA_OS)如何來創建程序進程映象

* 一個共享object文件保存着代碼和合適的數據,用來被下面的兩個鏈接器
  鏈接。第一個是連接編輯器 [請參看ld(SD_CMD)],可以和其他的可重定位和
  共享object文件來創建其他的object。第二個是動態鏈接器 ,聯合一個
  可執行文件和其他的共享object文件來創建一個進程映象。

一個object文件被彙編器和聯接器創建 , 想要在處理機上直接運行的object
文件都是以二進制來存放的。那些需要抽象機制的程序,比如象shell腳本,
是不被接受的。

在介紹性的材料過後,第一部分主要圍繞着文件的格式和關於如何建立程序。
第二部分也描述了object文件的幾個組成部分,集中在執行程序所必須的信息上。


     文件格式

Object文件參與程序的聯接( 創建一個程序)和程序的執行 (運行一個程序)。
object 文件格式提供了一個方便有效的方法並行的視角看待文件的內容,
在他們的活動中,反映出不同的需要。例 1-1圖顯示了一個object文件的
組織圖。

+ 圖1-1: Object文件格式

  Linking 視角                                           Execution 視角
  ============                                      ==============
  ELF header                                           ELF header
  Program header table (optional)           Program header table
  Section 1                                               Segment 1
  ...                                                           Segment 2
  Section n                                                ...
  Section header table                             Section header table (optional)

一個ELF頭 在文件的開始,保存了路線圖(road map),描述了該文件的組織情況。
sections保存着object 文件的信息,從連接角度看:包括指令,數據,
符號表,重定位信息等等。特別sections的描述會出現在以後的第一部分。
第二部分討論了段和從程序的執行角度看文件。

假如一個程序頭表(program header table)存在,那麼它告訴系統如何來創建一
個進程的內存映象
被用來建立進程映象(執行一個程序)的文件必須要有一個程
序頭表(program header table);可重定位文件不需要這個頭表。
一個
section頭表(section header table)包含了描述文件sections的信息。每個
section在這個表中有一個入口;每個入口給出了該section的名字,大小,
等等信息
。在連接過程中的文件必須有一個section頭表;其他object文件可要
可不要這個section頭表。

注意: 雖然圖顯示出程序頭表立刻出現在一個ELF頭後,section頭表跟着其他
section部分出現,事實上的文件是可以不同的。此外,sections和段(segments)
沒有特別的順序。只有ELF頭(elf header)是在文件的固定位置。


數據表示
object文件格式支持8位、32位不同的處理器。 不過,它試圖努力的在更大或更小的體系上運行。因此,object文件描繪一些控制數據需要用與機器無關的格式,使它儘可能的用一般的方法甄別object文件和描述他們的內容。在object文件中剩餘的數據使用目標處理器的編碼方式,不管文件是在哪臺機子上創建的。

+ 圖 1-2: 32-Bit Data Types

  Name                 Size   Alignment      Purpose
  ====                 ====  =========   =======
  Elf32_Addr           4       4                 Unsigned program address
  Elf32_Half            2       2                  Unsigned medium integer
  Elf32_Off             4       4                  Unsigned file offset
  Elf32_Sword        4       4                  Signed large integer
  Elf32_Word         4       4                  Unsigned large integer
  unsigned char     1       1                  Unsigned small integer

所有的object文件格式定義的數據結構是自然大小(natural size),爲相關的類型調整指針。如果需要,數據結構中明確的包含了確保4字節對齊的填充字段。來使結構大小是4的倍數。數據從文件的開始也有適當的對齊。
例如,一個包含了Elf32_Addr成員的結構將會在文件內對齊到4字節的邊界上。

因爲移植性的原因,ELF不使用位字段。


   ========================== ELF Header ==========================


一些object文件的控制結構能夠增長的,所以ELF頭包含了他們目前的大小。假如object文件格式改變,程序可能會碰到或大或小他 們不希望的控制結構。程序也有可能忽略額外(extra)的信息。對待來歷不明(missing)的信息依靠上下文來解釋,假如擴展被定義,它們將會被指 定。

+ 圖 1-3: ELF Header

  #define EI_NIDENT       16

  typedef struct {
      unsigned char       e_ident[EI_NIDENT];
      Elf32_Half          e_type;
      Elf32_Half          e_machine;
      Elf32_Word          e_version;
      Elf32_Addr          e_entry;
      Elf32_Off           e_phoff;
      Elf32_Off           e_shoff;
      Elf32_Word          e_flags;
      Elf32_Half          e_ehsize;
      Elf32_Half          e_phentsize;
      Elf32_Half          e_phnum;
      Elf32_Half          e_shentsize;
      Elf32_Half          e_shnum;
      Elf32_Half          e_shstrndx;
  } Elf32_Ehdr;

* e_ident(identification)

  這個最初的字段標示了該文件爲一個object文件,提供了一個機器無關
  的數據,解釋文件的內容。在下面的ELF的鑑別(ELF Identification)
  部分有更詳細的信息。

* e_type[elf type]

  該成員確定該object的類型。

               Name        Value  Meaning
               ====        =====  =======
               ET_NONE         0  No file type  // 什麼意思,還沒有類型?
               ET_REL          1  Relocatable file // 可以重定位的目標文件
               ET_EXEC         2  Executable file // 可執行文件
               ET_DYN          3  Shared object file // 共享文件,像動態庫、靜態庫等
               ET_CORE         4  Core file  // 這個是什麼類型的文件,我暫時也不清楚
               ET_LOPROC  0xff00  Processor-specific
               ET_HIPROC  0xffff  Processor-specific

  雖然CORE的文件內容未被指明,類型ET_CORE是保留的。
  值從 ET_LOPROC 到 ET_HIPROC(包括ET_HIPROC)是爲特殊的處理器保留的。
  如有需要,其他保留的變量將用在新的object文件類型上。

* e_machine

  該成員變量指出了運行該程序需要的體系結構。

                    Name      Value  Meaning
            ====      =====  =======
                    EM_NONE       0  No machine
      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

  如有需要,其他保留的值將用到新的機器類型上。特殊處理器名使用機器名來
  區別他們。例如,下面將要被提到的成員flags使用前綴EF_;在一臺EM_XYZ機器
  上,flag稱爲WIDGET,那麼就稱爲EF_XYZ_WIDGET。

* e_version

  這個成員確定object文件的版本。

                 Name         Value  Meaning
                 ====         =====  =======
                 EV_NONE          0  Invalid version
   EV_CURRENT       1  Current version

  值1表示原來的文件格式;創建新版本就用>1的數。EV_CURRENT值(上面給
  出爲1)如果需要將指向當前的版本號。

* e_entry

  該成員是系統第一個傳輸控制的虛擬地址,在那啓動進程。假如文件沒有
  如何關聯的入口點,該成員就保持爲0。

* e_phoff (program head offset)

  該成員保持着程序頭表(program header table)在文件中的偏移量(以字節計數)。
  假如該文件沒有程序頭表的的話,該成員就保持爲0。

* e_shoff (section head offset)

  該成員保持着section頭表(section header table)在文件中的偏移量(以字節
  計數)。假如該文件沒有section頭表的的話,該成員就保持爲0。

* e_flags

  該成員保存着相關文件的特定處理器標誌。
  flag的名字來自於EF_<machine>_<flag>。看下機器信息“Machine Information”
  部分的flag的定義。

* e_ehsize (elf head size)

  該成員保存着ELF頭大小(以字節計數)。

* e_phentsize (program head entry size)

  該成員保存着在文件的程序頭表(program header table)中一個入口的大小
  (以字節計數)。所有的入口都是同樣的大小。

* e_phnum (program head number)

  該成員保存着在程序頭表中入口的個數。因此,e_phentsize和e_phnum
  的乘機就是表的大小(以字節計數).假如沒有程序頭表(program header table),
  e_phnum變量爲0。

* e_shentsize (section head  entry size)

  該成員保存着section頭的大小(以字節計數)。一個section頭是在section
  頭表(section header table)的一個入口;所有的入口都是同樣的大小。

* e_shnum (section head nunber)

  該成員保存着在section header table中的入口數目。因此,e_shentsize和
  e_shnum的乘積就是section頭表的大小(以字節計數)。
  假如文件沒有section頭表,e_shnum值爲0。

* e_shstrndx

  該成員保存着跟section名字字符表相關入口的section頭表(section header
  table)索引。假如文件中沒有section名字字符表,該變量值爲SHN_UNDEF。
  更詳細的信息 看下面“Sections”和字符串表(“String Table”) 。


**  ELF 鑑別(Identification)
   在上面提到的,ELF提供了一個object文件的框架結構來支持多種處理機,多
   樣的數據編碼方式,多種機器類型。爲了支持這個object文件家族,最初的幾
   個字節指定用來說明如何解釋該文件,獨立於處理器,與文件剩下的內容無關。

    ELF頭(也就是object文件)最初的幾個字節與成員e_ident相一致。

+ 圖 1-4: e_ident[] Identification Indexes

  Name           Value  Purpose
  ====           =====  =======
  EI_MAG0      0  File identification
  EI_MAG1      1  File identification
  EI_MAG2      2  File identification
  EI_MAG3      3  File identification
  EI_CLASS      4  File class
  EI_DATA      5  Data encoding
  EI_VERSION      6  File version
  EI_PAD      7  Start of padding bytes
  EI_NIDENT     16  Size of e_ident[]

通過索引訪問字節,以下的變量被定義。

* EI_MAG0 to EI_MAG3

  文件的前4個字符保存着一個魔術數(magic number),用來確定該文件是否
  爲ELF的目標文件。

                  Name       Value  Position
                  ====       =====  ========
      ELFMAG0    0x7f   e_ident[EI_MAG0]
                  ELFMAG1    'E'    e_ident[EI_MAG1]
                  ELFMAG2    'L'    e_ident[EI_MAG2]
                  ELFMAG3    'F'    e_ident[EI_MAG3]

* EI_CLASS

  接下來的字節是e_ident[EI_CLASS],用來確定文件的類型或者說是能力。

                 Name           Value  Meaning
                 ====           =====  =======
                 ELFCLASSNONE       0  Invalid class
                 ELFCLASS32         1  32-bit objects
   ELFCLASS64         2  64-bit objects

  文件格式被設計成在不同大小機器中可移植的,在小型機上的不用大型機上
  的尺寸。類型ELFCLASS32支持虛擬地址空間最大可達4GB的機器;使用上面
  定義過的基本類型。

  類型ELFCLASS64爲64位體系的機器保留。它的出現表明了object文件可能
  改變,但是64位的格式還沒有被定義。如果需要,其他類型將被定義,會
  有不同的類型和不同大小的數據尺寸。

* EI_DATA (編碼方式)

  字節e_ident[EI_DATA]指定了在object文件中特定處理器數據的編碼
  方式。當前定義了以下編碼方式。

             Name           Value  Meaning
             ====           =====  =======
     ELFDATANONE        0  Invalid data encoding
             ELFDATA2LSB        1  See below
             ELFDATA2MSB        2  See below

  更多的關於編碼的信息出現在下面。其他值保留,將被分配一個新的編碼
  方式,當然如果必要的話。

* EI_VERSION

  字節e_ident[EI_VERSION]表明了ELF頭的版本號。
  現在這個變量的是一定要設爲EV_CURRENT,作爲上面e_version的解釋。

* EI_PAD

  該變量標識了在e_ident中開始的未使用的字節。那些字節保留並被設置爲
  0;程序把它們從object 文件中讀出但應該忽略。假如當前未被使用的字節
  有了新的定義,EI_PAD變量將來會被改變。

  一個文件的數據編碼指出瞭如何來解釋一個基本的object文件。在上述的
  描述中,類型ELFCLAS32文件使用佔用1,2和4字節的目標文件。下面定義的
  編碼方式,用下面的圖來描繪。數據出現在左上角。


  ELFDATA2LSB編碼指定了2的補數值。
  最小有意義的字節佔有最低的地址。
    這裏就是指所爲的大頂端、小頂端(little endian or big endian)

+ 圖1-5: Data Encoding ELFDATA2LSB

               0------+
      0x0102   |  01  |
               +------+
               0------1------+
    0x010204   |  02  |  01  |
               +------+------+
               0------1------2------3------+
  0x01020304   |  04  |  03  |  02  |  01  |
               +------+------+------+------+

ELFDATA2LSB編碼指定了2的補數值。
最大有意義的字節佔有最低的地址。

+ 圖1-6: Data Encoding ELFDATA2MSB

               0------+
      0x0102   |  01  |
               +------+
               0------1------+
    0x010204   |  01  |  02  |
               +------+------+
               0------1------2------3------+
  0x01020304   |  01  |  02  |  03  |  04  |
               +------+------+------+------+


**機器信息

***爲了確定文件,32位Intel體系結構的需要以下的變量。

 + 圖1-7: 32-bit Intel Architecture Identification, e_ident

  Position           Value
  ========           =====
  e_ident[EI_CLASS]  ELFCLASS32
  e_ident[EI_DATA]   ELFDATA2LSB

處理器確認ELF頭裏的e_machine成員,該成員必須爲EM_386。

ELF報頭裏的e_flags成員保存了和文件相關的位標記。32位Intel體系上未
定義該標記;所以這個成員應該爲0;


   =========================== Sections ===========================


一個object文件的section header table可以讓我們定位所有的sections。
section header table是個Elf32_Shdr結構的數組(下面描述)。一個section
報頭表(section header table)索引是這個數組的下標。ELF header table
的e_shoff成員給出了section報頭表的偏移量(從文件開始的計數)。e_shnum
告訴我們section報頭表中包含了多少個入口;e_shentsize 給出了每個
入口的大小。

一些section報頭表索引是保留的;那些特別的索引在一個object文件中
將沒有與之對應sections。

+ 圖1-8: Special Section Indexes

  Name             Value
  ====             =====
  SHN_UNDEF            0
  SHN_LORESERVE   0xff00
  SHN_LOPROC      0xff00
  SHN_HIPROC      0xff1f
  SHN_ABS         0xfff1
  SHN_COMMON      0xfff2
  SHN_HIRESERVE   0xffff

* SHN_UNDEF

  該值表明沒有定義,缺少,不相關的或者其他涉及到的無意義的section。
  例如,標號“defined”相對於section索引號SHN_UNDEF是一個沒有被
  定義的標號。

注意: 雖然索引0保留作爲未定義的值,section報頭表包含了一個索引0的
入口。因此,假如ELF報頭說一個文件的section報頭表中有6個section入口
的話,e_shnum的值應該是從0到5。最初的入口的內容以後在這個section中
被指定。

* SHN_LORESERVE

  該值指定保留的索引範圍的最小值。

* SHN_LOPROC through SHN_HIPROC

  該值包含了特定處理器語意的保留範圍。


* SHN_ABS

  該變量是相對於相應參考的絕對地址。
  例如,section號的標號是絕對地址,不被重定位影響。

* SHN_COMMON

  該section的標號是一個公共(common)的標號,就象FORTRAN COMMON
  或者不允許的C擴展變量。

* SHN_HIRESERVE

  該值指定保留的索引範圍的上限。系統保留的索引值是從SHN_LORESERVE
  到SHN_HIRESERVE;該變量不涉及到section報頭表(section header table)。
  因此,section報頭表不爲保留的索引值包含入口。

sections包含了在一個object文件中的所有信息,除了ELF報頭,程序報頭
表(program header table),和section報頭表(section header table)。
此外,object文件的sections滿足幾天條件:

* 每個在object文件中的section都有自己的一個section的報頭來描述它。
  section頭可能存在但section可以不存在。
* 每個section在文件中都佔有一個連續順序的空間(但可能是空的)。
* 文件中的Sections不可能重複。文件中沒有一個字節既在這個section中
  又在另外的一個section中。
* object文件可以有"非活動的"空間。不同的報頭和sections可以不覆蓋到
  object文件中的每個字節。"非活動"數據內容是未指定的。

一個section頭有如下的結構。

+ 圖1-9: Section Header

  typedef struct {
      Elf32_Word sh_name;
      Elf32_Word sh_type;
      Elf32_Word sh_flags;
      Elf32_Addr sh_addr;
      Elf32_Off sh_offset;
      Elf32_Word sh_size;
      Elf32_Word sh_link;
      Elf32_Word sh_info;
      Elf32_Word sh_addralign;
      Elf32_Word sh_entsize;
  } Elf32_Shdr;

* sh_name

  該成員指定了這個section的名字。它的值是section報頭字符表section的
  索引。[看以下的“String Table”], 以NULL空字符結束。

* sh_type

  該成員把sections按內容和意義分類。section的類型和他們的描述在下面。

* sh_flags

  sections支持位的標記,用來描述多個屬性。 
  Flag定義出現在下面。

* sh_addr

  假如該section將出現在進程的內存映象空間裏,該成員給出了一個該section
  在內存中的位置。否則,該變量爲0。

* sh_offset

  該成員變量給出了該section的字節偏移量(從文件開始計數)。SHT_NOBITS
  類型的section(下面討論)在文件中不佔空間,它的sh_offset成員定位在
  文件中的概念上的位置。

* sh_size
  該成員給你了section的字節大小。除非這個section的類型爲SHT_NOBITS,
  否則該section將在文件中將佔有sh_size個字節。SHT_NOBITS類型的section
  可能爲非0的大小,但是不佔文件空間。

* sh_link

  該成員保存了一個section報頭表的索引連接,它的解釋依靠該section的
  類型。以下一個表描述了這些值。

* sh_info

  該成員保存着額外的信息,它的解釋依靠該section的類型。以下一個表描
  述了這些值。

* sh_addralign

  一些sections有地址對齊的約束。例如,假如一個section保存着雙字,系統
  就必須確定整個section是否雙字對齊。所以sh_addr的值以sh_addralign的值
  作爲模,那麼一定爲0。當然的,僅僅0和正的2的次方是允許的。值0和1意味
  着該section沒有對齊要求。

* sh_entsize

  一些sections保存着一張固定大小入口的表,就象符號表。對於這樣一個
  section來說,該成員給出了每個入口的字節大小。如果該section沒有
  保存着一張固定大小入口的表,該成員就爲0。

section頭成員sh_type指出了section的語意。

+ 圖1-10: Section Types, sh_type

  Name               Value
  ====               =====
  SHT_NULL               0
  SHT_PROGBITS           1
  SHT_SYMTAB             2
  SHT_STRTAB          3
  SHT_RELA          4
  SHT_HASH          5
  SHT_DYNAMIC            6
  SHT_NOTE          7
  SHT_NOBITS          8
  SHT_REL          9
  SHT_SHLIB             10
  SHT_DYNSYM            11
  SHT_LOPROC    0x70000000
  SHT_HIPROC    0x7fffffff
  SHT_LOUSER    0x80000000
  SHT_HIUSER    0xffffffff

* SHT_NULL

  該值表明該section頭是無效的;它沒有相關的section。
  該section的其他成員的值都是未定義的。

* SHT_PROGBITS

  該section保存被程序定義了的一些信息,它的格式和意義取決於程序本身。

* SHT_SYMTAB and SHT_DYNSYM

  那些sections保存着一個符號表(symbol table)。一般情況下,一個
  object文件每個類型section僅有一個,但是,在將來,這個約束可能被放寬。
  典型的是,SHT_SYMTAB爲連接器提供標號,當然它也有可能被動態連接時使用。
  作爲一個完整的符號表,它可能包含了一些動態連接時不需要的標號。
  因此,一個object文件可能也包含了一個SHT_DYNSYM的section,它保存着
  一個動態連接時所需最小的標號集合來節省空間。
  看下面符號表“Symbol Table”的細節。

* SHT_STRTAB

  該section保存着一個字符串表。一個object文件可以包含多個字符串表的
  section。看下面字符串表“String Table”的細節。

* SHT_RELA

  該section保存着具有明確加數的重定位入口。就象object文件32位的
  Elf32_Rela類型。一個object文件可能有多個重定位的sections。具體細節
  看重定位``Relocation''部分。

* SHT_HASH

  該標號保存着一個標號的哈希(hash)表。所有的參與動態連接的object
  一定包含了一個標號哈希表(hash table)。當前的,一個object文件
  可能只有一個哈希表。詳細細節看第二部分的哈希表"Hash Table"。

* SHT_DYNAMIC

  該section保存着動態連接的信息。當前的,一個object可能只有一個動態
  的section,但是,將來這個限制可能被取消。詳細細節看第二部分的動態
  section(“Dynamic Section”)。

* SHT_NOTE

  該section保存着其他的一些標誌文件的信息。詳細細節看第二部分的“Note
  Section” 。

* SHT_NOBITS

  該類型的section在文件中不佔空間,但是類似SHT_PROGBITS。儘管該section
  不包含字節,sh_offset成員包含了概念上的文件偏移量。

* SHT_REL

  該section保存着具有明確加數的重定位的入口。
  就象object文件32位類型Elf32_Rel類型。一個object文件可能有多個
  重定位的sections。具體細節看重定位``Relocation''部分。

* SHT_SHLIB

  該section類型保留但語意沒有指明。包含這個類型的section的程序
  是不符合ABI的。

* SHT_LOPROC through SHT_HIPROC

  在這範圍之間的值爲特定處理器語意保留的。

* SHT_LOUSER

  該變量爲應用程序保留的索引範圍的最小邊界。

* SHT_HIUSER

  該變量爲應用程序保留的索引範圍的最大邊界。在SHT_LOUSER和HIUSER的
  section類型可能被應用程序使用,這和當前或者將來系統定義的section
  類型是不矛盾的。

其他section類型的變量是保留的。前面提到過,索引0(SHN_UNDEF)的section
頭存在的,甚至索引標記的是未定義的section引用。這個入口保存着以下的
信息。

+ 圖1-11: Section Header Table Entry: Index 0

  Name            Value    Note
  ====            =====    ====
  sh_name           0      No name
  sh_type        SHT_NULL  Inactive
  sh_flags          0      No flags
  sh_addr           0      No address
  sh_offset         0      No file offset
  sh_size           0      No size
  sh_link SHN_UNDEF  No link information
  sh_info     0      No auxiliary information
  sh_addralign     0      No alignment
  sh_entsize        0      No entries

一個section報頭(section header table)的sh_flags成員保存着1位標記,
用來描述section的屬性。以下是定義的值;其他的值保留。

+ 圖1-12: Section Attribute Flags, sh_flags

  Name                Value
  ====                =====
  SHF_WRITE             0x1
  SHF_ALLOC             0x2
  SHF_EXECINSTR         0x4
  SHF_MASKPROC   0xf0000000

假如在sh_flags中的一個標記位被設置,該section相應的屬性也被打開。
否則,該屬性沒有被應用。未明的屬性就設爲0。

* SHF_WRITE

  該section包含了在進程執行過程中可被寫的數據。

* SHF_ALLOC

  該section在進程執行過程中佔據着內存。一些控制section不存在一個
  object文件的內存映象中;對於這些sections,這個屬性應該關掉。

* SHF_EXECINSTR

  該section包含了可執行的機器指令。

* SHF_MASKPROC

  所有的包括在這掩碼中的位爲特定處理語意保留的。

在section報頭中,兩個成員sh_link和sh_info的解釋依靠該section的類型。

+ 圖1-13: sh_link and sh_info Interpretation

  sh_type      sh_link                        sh_info
  =======      =======                        =======
  SHT_DYNAMIC  The section header index of    0
               the string table used by
               entries in the section.
  SHT_HASH     The section header index of    0
               the symbol table to which the
               hash table applies.
  SHT_REL,     The section header index of    The section header index of
  SHT_RELA     the associated symbol table.   the section to which the
                                              relocation applies.
  SHT_SYMTAB,  The section header index of    One greater than the symbol
  SHT_DYNSYM   the associated string table.   table index of the last local
                                              symbol (binding STB_LOCAL).
  other        SHN_UNDEF                      0


Special Sections   特殊的Sections

不同的sections保存着程序和控制信息。下面列表中的section被系統使用,
指示了類型和屬性。

+ 圖1-14: Special Sections

  Name         Type           Attributes
  ====         ====           ==========
  .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    see below
  .dynstr      SHT_STRTAB     SHF_ALLOC
  .dynsym      SHT_DYNSYM     SHF_ALLOC
  .fini        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR
  .got         SHT_PROGBITS   see below
  .hash        SHT_HASH       SHF_ALLOC
  .init        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR
  .interp      SHT_PROGBITS   see below
  .line        SHT_PROGBITS   none
  .note        SHT_NOTE       none
  .plt         SHT_PROGBITS   see below
  .rel<name>   SHT_REL        see below
  .rela<name>  SHT_RELA       see below
  .rodata      SHT_PROGBITS   SHF_ALLOC
  .rodata1     SHT_PROGBITS   SHF_ALLOC
  .shstrtab    SHT_STRTAB     none
  .strtab      SHT_STRTAB     see below
  .symtab      SHT_SYMTAB     see below
  .text        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR

* .bss

  該sectiopn保存着未初始化的數據,這些數據存在於程序內存映象中。
  通過定義,當程序開始運行,系統初始化那些數據爲0。該section不佔
  文件空間,正如它的section類型SHT_NOBITS指示的一樣。
 
* .comment

   該section保存着版本控制信息。

* .data and .data1
  這些sections保存着初始化了的數據,那些數據存在於程序內存映象中。

* .debug

  該section保存着爲標號調試的信息。該內容是未指明的。

* .dynamic

  該section保存着動態連接的信息。該section的屬性將包括SHF_ALLOC位。
  是否需要SHF_WRITE是跟處理器有關。第二部分有更詳細的信息。

* .dynstr

  該section保存着動態連接時需要的字符串,一般情況下,名字字符串關聯着
  符號表的入口。第二部分有更詳細的信息。

* .dynsym

  該section保存着動態符號表,如“Symbol Table”的描述。第二部分有更
  詳細的信息。
 
* .fini

  該section保存着可執行指令,它構成了進程的終止代碼。
  因此,當一個程序正常退出時,系統安排執行這個section的中的代碼。

* .got

  該section保存着全局的偏移量表。看第一部分的“Special Sections”和
  第二部分的“Global Offset Table”獲得更多的信息。

* .hash

  該section保存着一個標號的哈希表。看第二部分的“Hash Table”獲得更多
  的信息。

* .init

  該section保存着可執行指令,它構成了進程的初始化代碼。
  因此,當一個程序開始運行時,在main函數被調用之前(c語言稱爲main),
  系統安排執行這個section的中的代碼。

* .interp

  該section保存了程序的解釋程序(interpreter)的路徑。假如在這個section
  中有一個可裝載的段,那麼該section的屬性的SHF_ALLOC位將被設置;否則,
  該位不會被設置。看第二部分獲得更多的信息。

* .line

  該section包含編輯字符的行數信息,它描述源程序與機器代碼之間的對於
  關係。該section內容不明確的。

* .note

  該section保存一些信息,使用“Note Section”(在第二部分)中提到的格式。

* .plt

  該section保存着過程連接表(Procedure Linkage Table)。看第一部分的
  ``Special Sections''和第二部分的“Procedure Linkage Table”。

* .rel<name> and .rela<name>

  這些section保存着重定位的信息,看下面的``Relocation''描述。
  假如文件包含了一個可裝載的段,並且這個段是重定位的,那麼該section的
  屬性將設置SHF_ALLOC位;否則該位被關閉。按照慣例,<name>由重定位適用
  的section來提供。因此,一個重定位的section適用的是.text,那麼該名字
  就爲.rel.text或者是.rela.text。

* .rodata and .rodata1

  這些section保存着只讀數據,在進程映象中構造不可寫的段。看第二部分的
  ``Program Header''獲得更多的資料。

* .shstrtab

  該section保存着section名稱。

* .strtab

  該section保存着字符串,一般地,描述名字的字符串和一個標號的入口相關
  聯。假如文件有一個可裝載的段,並且該段包括了符號字符串表,那麼section
  的SHF_ALLOC屬性將被設置;否則不設置。

* .symtab

  該section保存着一個符號表,正如在這個section裏``Symbol Table''的
  描述。假如文件有一個可裝載的段,並且該段包含了符號表,那麼section
  的SHF_ALLOC屬性將被設置;否則不設置。

* .text

  該section保存着程序的``text''或者說是可執行指令。


前綴是點(.)的section名是系統保留的,儘管應用程序可以用那些保留的
section名。應用程序可以使用不帶前綴的名字以避免和系統的sections
衝突。object文件格式可以讓一個定義的section部分不出現在上面的列
表中。一個object文件可以有多個同樣名字的section。

爲處理器體系保留的section名的形成是通過置換成一個體系名的縮寫。
該名字應該取自體系名,e_machine使用的就是。例如,.Foo.psect就是
在FOO體系上定義的名字。

現存的擴展名是歷史遺留下來的。

       Pre-existing Extensions
       =======================
.sdata     .tdesc
.sbss      .lit4
.lit8      .reginfo
.gptab     .liblist
.conflict

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章