文章來源:華清遠見嵌入式學院,原文地址:http://www.embedu.org/Column/Column699.htm
作者:馮老師,華清遠見嵌入式學院講師。
1. 程式源碼如下:
2.命令
gcc –E simple_section.c –o simple_section.i
gcc –S simple_section.i –o simple_section.s
gcc –c simple_section.s –o simple_section.o
gcc simple_section.o –o a.out
3. Elf檔案頭
ELF目標檔案格式的最前部是ELF檔案頭,它包含了描述整個檔案的基本屬性,包括ELF魔數、檔案機器位元組長度、資料存放區方式、版本、運行平台、ABI版本、ELF重定位類型、硬體平台、硬體平台版本、入口地址、程式頭入口和長度、段表的位置和長度及段的數量等。
檔案頭的結構體定義如下:
使用”readelf –h”命令可以查看目標檔案標頭檔的內容:
magic是結構體的第一個成員e_indent,16個位元組:
最開始的4個位元組是所有的ELF檔案都必須相同的標識碼,分別為0x7f, 0x45, 0x4c,0x 46。第一個位元組對應ASCII字元裡的DEL控制符,後面3個位元組剛好是ELF這三個字母的ASCII值。
4. 段表
ELF檔案中有很多段,段表就是儲存這些段的基本屬性的結構。包括每個段的段名、段的長度、在檔案中的位移、讀寫權限及段的其他屬性。也就是說ELF檔案段的結構式由段表決定的,編譯器、連接器和裝載器都是依靠段表來定位和訪問各個段的屬性的。
段表的定義如下:
“objdump –h”命令只是顯示關鍵段,省略了輔助性的段。”readelf -S”命令顯示的更完整。
已初始化的全域變數和局部靜態變數,都儲存在.data段。未初始化的全域變數和局部靜態變數一般放在.bss段。
但是,這個例子裡,bss段只佔4個位元組。
通過下面的符號表,可以看出只有static_var2變數放在了bss段中,global_uninit_var並沒有放在任何的,只是一個未定義的“COMMON符號”,這和編譯器有關,全域的未初始設定變數,有的放在bss 段,有的則不放,只是預留一個未定義的全域變數符號,等到最終連結成可執行檔的時候,再在bss段分配空間。
備忘:
1).bss段在”objdump -h”的輸出結果中,沒有“CONTENTS”,因此不存在。
2).comment段:存放的是編譯器版本資訊,比如字串“GCC:(GNU)4.2.0”
3).shstrtab : Section String Table.段名表
4).strtab:string table字串表
5).symtab: Symbol Table符號表
6).rel.text: 告訴連結器指令中的哪些地方需要做重定位
7)命令可以顯示所有段的內容。
8).hexdump –C simple_section.o 命令,可以把目標檔案中的所有位元組都列印出來。
start of section headers是372位元組,十六進位後是0x00000174。和中section table的起始地址是一致的。
再結合”readelf –S simple_section”的結果,注意Al屬性,會有對齊,可以畫出下面的圖:
最後的0x51c剛好是1308位元組,是simple_section.o的大小。