ELF(Executable and Linking Format)格式教學文件, #5: 讀 ELF Section(說明)

jollen 發表於 November 28, 2006 5:14 PM

今天的內容「讀取 ELF section」是這系列 ELF 文章的重點戲。因為我們終於進入 ELF 的核心議題「節區的觀念」了。在 loader v0.5 以前的範例,都是屬於靜態的討論(linking view);在 loader v0.6 開始的討論中,我們將會開始提到動態的執行行為(execution view)。

如何讀取 ELF Section

我們分 2 個步驟來讀取 ELF 的 section 資訊:

1. 如圖一,一開始先讀取 section header table 的資訊。section header table 是所有 section 的紀錄表格,所有的 section 都要透過 section header table 才能得知其在檔案中的偏移位置(offset),如此一來才能讀取 section 的內容。

2. 如圖二,接著再根據 section header table 讀取檔案裡的每一個 section。

section header table 裡的 section 個數(section entries)紀錄於 ELF header 裡的 e_shnum 欄位,每個 section entry 的長度則是紀錄在 ELF header 的 e_shentsize 欄位,單位是bytes。

elf_sht.jpg
圖一:Section Header Table

ELF header 裡的 e_shoff 欄位,是 section header table 開始的檔案偏移位置 (file offset)。因此,我們只要由 e_shoff 偏移值開始讀取 e_shnum 個單位,每個單位為 e_shentsize(bytes),即可將整個 section header table 讀取出來。

elf_section_entry.jpg
圖二:Section Entries

SysV ABI 定義 section entry 的資料結構如下:

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;

Section header table 是 Elf32_Shdr data type 的陣列,其元素個數為 e_shnum,我們可以透過索引 Elf32_Shdr 陣列來讀取所有的 section,如圖二所示。

Section header(Elf32_Shdr)的欄位用途說明如下表。

Field Description
sh_name  section的名稱,需由string table查表取得。
sh_type  section的類型。
sh_flags  section的屬性。
sh_addr  section在記憶體裡的起始位址,但並非所有的section都會被載入至記憶體。
sh_offset  section在objct file裡的開始偏移值(offset),程式必須根據此欄位來讀取section的本文。
sh_size  section的長度(bytes)。
sh_link  可用來存放section header table的index link。
sh_info  可用來存放section的額外資訊。
sh_addralign  紀錄section的address alignment,例如有些section的 alignment為DWORD(dobuleword)。
sh_entsize  有些section的內容為entry長度固定的table,例如symbol table。此欄用來紀錄entry的長度,單位是bytes。

範例程式:loader v0.3

接著說明 loader v0.2 需要改寫的功能。

在主程式新增一個 parse_sections() 函數來讀取 ELF object file 的 section header table:

parse_sections(&f_header, fd);

parse_sections() 負責做2件工作:

1. 讀取 Section Header Table

2. 找出 Section Name String Table

同時,在主程式也要加入以下 2 個變數:

Elf32_Shdr header[40];
Elf32_Shdr *strtab; /* point to string table */

header[] 用來存放由 section header table 所讀取出來的所有 section entry,其型別為 Elf32_Shdrstrtab 指標用來指向 section name string table,其型別為 Elf32_Shdr。Section name string table 是一個特殊的 section,下一個範例再來處理這個 section。

將檔案讀寫指標移到 e_shoff 的地方,準備開始讀取 section header table:

lseek(fd, hdr->e_shoff, SEEK_SET);

然後再利用最簡單的方式,一次一個將所有的section entry讀取出來,並且判斷該section entry是否為string table:

   for (i = 0; i < hdr->e_shnum; i++) {
      read(fd, &header[i], sizeof(Elf32_Shdr));

      /* find out string table ! */
      if (header[i].sh_type == SHT_STRTAB) strtab = &header[i];
   }

最後,section 用途是根據他的類型來區分的,這個部份留待下次再做說明。

Also See

Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue

您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw