根據 SysV ABI 的定義,若 section 的類型為 SHT_STRTAB,則該 section entry 即為 string table 的 section header。Section 的類型可由 section header 的 sh_type 欄位來判斷,SysV ABI 定義的 section 類型(sh_type)如下表所示。
表 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 |
我們在範例程式 loader-0.3.c 中,試著由一堆的 section 裡找出類型為 string table(SHT_STRTAB)的section。接下來程式 loader-0.4.c 將會試著實作讀取 ELF 的 string table,並將有 section 的名稱印出。
讀取 Section Name String Table
String table 是一個特殊的 section,此 section 紀錄所有 section 的名稱(ASCII 字串)。String table 是一個字元型別的陣列,每一個 section 都會有一個索引值來索引自己的 section name 字串,section header 的 sh_name 欄位則是存放了此索引值,如圖所示。
圖 ELF section name string table
程式說明
呼叫了 parse_sections() 函數來讀取section header table:
parse_sections(&f_header, fd);
相較於 loader-0.3.c 的 parse_sections() 函數,在 0.4 的版本裡,我們所做的改變如下:
1. 讀取 string table 的內容
2. 列印所有 section 的名稱
首先,我們新增一個陣列來存放 string table 的內容:
char strtab[65535];
接下來一樣讀取所有的 section entry,並且找出 string table:
for (i = 0; i < hdr->e_shnum; i++) { read(fd, &header_ent[i], sizeof(Elf32_Shdr)); /* load section name string table */ if (i == hdr->e_shstrndx) { sh_strtab = &header_ent[i]; } }
我們試著用另外一種方法來找出 string table 吧!根據 SysV ABI 的定義,string table 在 section header table 裡的 section entry index(索引值)紀錄在 ELF header 的 e_shstrndx 欄位,因此,我們判斷目前的 section header table 索引值是否等於 e_shstrndx 來找出 string table。接下來再讀取string table 的內容:
/* read “String Table” */ lseek(fd, sh_strtab->sh_offset, SEEK_SET); read(fd, strtab, sh_strtab->sh_size);
程式裡利用 lseek() 函數將檔案讀寫指標移 string table 開始的地方,然後再將整個 string table 讀出。要注意的是,section 的長度紀錄於 section header裡的 sh_size 欄位。最後再逐一將每個section的名稱列印在螢幕上:
/* Index 0: undefined */ for (i = 1; i < hdr->e_shnum; i++) { printf("%s\n", &strtab[header_ent[i].sh_name]); }
小結
我們知道一個很重要的觀念了。ELF section 的字串名稱是由 string table 查表得知,section 名稱在 string table 陣列裡的索引值則是紀錄在 section header 裡的 sh_name 欄位。