ELF Section Header的結構還是要從/usr/include/elf.h中看。
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;
同樣,可以算出來Elf32_Shdr的大小是40B。其結構中的各個元素資料類型在elf.h中同樣可以找到,含義見注釋。整個section header table就是一個數組,數組的每一個元素就是Elf32_Shdr。Elf32_Shdr僅僅是section的一個索引,包括一些屬性資訊,并不是section本省。簡單的介紹一下各個元素的含義。
sh_name: section name。不過其實sh_name中存放的是index,不是字元串,這一點從sh_name是定長應該能看出來,那麼index又是什麼意思呢?index的含義是在string tabl總的第幾個位元組數。其實是這樣的,所有的section name都存放在一個叫做string table的表中,index就是該section名字的第一個字元在表中的位置,名字一直到遇到一個'\0'為止結束。至于string table怎麼找,還記得上一篇中提到的elf header中的e_shstrndx成員嗎,它就指明了string table是在section header table中的第幾個入口。
sh_offset:這個元素就指明了這個Elf32_Shdr描述的section在檔案中的偏移量。
其他各個變量可以查詢《Executable and Linkable Format(ELF)》這個文檔。
為了檢驗程式輸出結果的對錯,我們與readelf這個指令的輸出結果作比較。
下面程式設計式來輸出檔案的section資訊。首先要找到section header table在檔案中的位置,回憶一下,section header table的偏移量在elf header中的e_shoff中告訴了我們,是以,我們就知道了section header table在檔案中的位置了,同樣,我們在elf header中可以找到section header的大小及個數,這樣我們用一個循環就可以輸出出來每個section的資訊了。
fseek(fp, elfheader.e_shoff, SEEK_SET);
shnum = elfheader.e_shnum;
printf("Number of Section headers: %d\n\n", shnum);
while(shnum != 0){
fread(&shdr, sizeof(char), sizeof(shdr), fp);
printf("sh_name : %d\n", shdr.sh_name);
printf("sh_type : %#x\n", shdr.sh_type);
printf("sh_flags : %d\n", shdr.sh_flags);
printf("sh_addr : %#x\n", shdr.sh_addr);
printf("sh_offset : %d\n", shdr.sh_offset);
printf("sh_size : %d\n", shdr.sh_size);
printf("sh_link : %d\n", shdr.sh_link);
printf("sh_info : %d\n", shdr.sh_info);
printf("sh_addralign : %d\n", shdr.sh_addralign);
printf("sh_entsize : %d\n\n", shdr.sh_entsize);
shnum--;
}
輸出的結果如下:
Number of Section headers: 34
sh_name : 0
sh_type : 0
sh_flags : 0
sh_addr : 0
sh_offset : 0
sh_size : 0
sh_link : 0
sh_info : 0
sh_addralign : 0
sh_entsize : 0
sh_name : 27
sh_type : 0x1
sh_flags : 2
sh_addr : 0x80480f4
sh_offset : 244
sh_size : 19
sh_link : 0
sh_info : 0
sh_addralign : 1
sh_entsize : 0
sh_name : 35
sh_type : 0x7
sh_flags : 2
sh_addr : 0x8048108
sh_offset : 264
sh_size : 32
sh_link : 0
sh_info : 0
sh_addralign : 4
sh_entsize : 0
...
觀察上面的結果可以看到,sh_name并不是section的名字,而是一個數字。回憶前面提到的,sh_name存放的隻是section name在string table的index。是以,為了輸出section name我們必須先得到string table。string table的資訊也在section header table中存放,隻要我們得到了string table header的内容,就可以從裡面的sh_offset知道string table的位置,從sh_size知道string table的大小。此時問題就成為如何找到string talbe header在section header table中的位置,即index.回憶前面講到的,elf header中有一個變量e_shstrndx存放的就是string table header在section header中的index。此時整個思路已經明白了,即elfheader.e_shstrndx --> string table header --> string table。string table裡面到底是什麼呢?其實就是一些帶'\0'的字元串。比如\0.bss\0.text\0\0,那麼如果sh_name是1,則該sh_name代表的是從string table中零開始的直到遇到\0為止的字元串,即.bss。整個程式如下:
fseek(fp, elfheader.e_shoff + elfheader.e_shstrndx*elfheader.e_shentsize, SEEK_SET);
fread(&strhdr, sizeof(char), sizeof(strhdr), fp);//get the string table header
fseek(fp, strhdr.sh_offset, SEEK_SET);
strtable = (unsigned char *)malloc(sizeof(unsigned char)*strhdr.sh_size);
fread(strtable, sizeof(char), strhdr.sh_size, fp);
fseek(fp, elfheader.e_shoff, SEEK_SET);
shnum = elfheader.e_shnum;
printf("Number of Section headers: %d\n\n", shnum);
while(shnum != 0){
fread(&shdr, sizeof(char), sizeof(shdr), fp);
printf("sh_name : %s\n", strtable+shdr.sh_name);
printf("sh_type : %#x\n", shdr.sh_type);
printf("sh_flags : %d\n", shdr.sh_flags);
printf("sh_addr : %#x\n", shdr.sh_addr);
printf("sh_offset : %d\n", shdr.sh_offset);
printf("sh_size : %d\n", shdr.sh_size);
printf("sh_link : %d\n", shdr.sh_link);
printf("sh_info : %d\n", shdr.sh_info);
printf("sh_addralign : %d\n", shdr.sh_addralign);
printf("sh_entsize : %d\n\n", shdr.sh_entsize);
shnum--;
}
程式的輸出結果為:
Number of Section headers: 34
sh_name :
sh_type : 0
sh_flags : 0
sh_addr : 0
sh_offset : 0
sh_size : 0
sh_link : 0
sh_info : 0
sh_addralign : 0
sh_entsize : 0
sh_name : .interp
sh_type : 0x1
sh_flags : 2
sh_addr : 0x80480f4
sh_offset : 244
sh_size : 19
sh_link : 0
sh_info : 0
sh_addralign : 1
sh_entsize : 0
sh_name : .note.ABI-tag
sh_type : 0x7
sh_flags : 2
sh_addr : 0x8048108
sh_offset : 264
sh_size : 32
sh_link : 0
sh_info : 0
sh_addralign : 4
sh_entsize : 0
sh_name : .hash
sh_type : 0x5
sh_flags : 2
sh_addr : 0x8048128
sh_offset : 296
sh_size : 64
sh_link : 4
sh_info : 0
sh_addralign : 4
sh_entsize : 4