C/C++代碼通過編譯後會生成elf文件,裏面包含了平臺、代碼、數據,調試信息等。linux
編譯過程參考:https://blog.csdn.net/qq_39815222/article/details/108526580網絡
1. elf文件格式
- ELF Header
連接後的elf文件有三種類型,分別是可重定位文件rel(包含適合於與其餘目標文件連接來建立可執行文件,或者共享目標文件的代碼和數據);可執行文件exec(包含適合於執行的的一個程序,此文件規定了exec()如何建立一個程序的進程映像);共享目標文件dyn(包含可在兩種上下文連接的代碼和數據,如linux中已.so結尾的文件)
簡寫爲Ehdr, 包含如下信息:
e_ident[**] //elf標識
e_type; //elf類型(上述三種類型)
e_ machine; //目標文件體系類型,即運行架構,如x8六、riscv、arm等
e_version; //目標文件版本
e_entry; //elf入口地址
e_ phoff; //程序頭部偏移
e_shoff; //節區頭部偏移
e_flags;
e_ehsize; //ELF格式頭部大小
e_phentsize; //程序頭部表項大小
e_phnum; //程序頭表項個數,即segment數
e_shentsize; //節區頭部表項大小
e_shnum; //節區表項個數,即section數
e_shstrndx;架構
- Program Header Table
簡寫爲Phdr,包含如下信息:
p_type; //segment類型
p_offset; //segment在文件中的偏移
p_vaddr; //segment虛地址
p_paddr; //物理地址
p_filesz; //文件中segment字節數
p_memsz; //內存中segment字節數
p_flags;
p_align;ide
- segment
內容包括text segment,data segment等,segment包含多個section,
- .text
已編譯程序的指令代碼段 - .rodata
ro表明read only,表示只讀數據 - .data
已初始化的C程序全局變量和靜態局部變量。C程序普通變量在運行是被保存在堆棧中,既不在.data中,也不在.bss中,此外,若是變量初始化值爲0,也可能會放到bss段。 - .bss
未初始化的C程序變量和靜態局部變量。目標文件格式區分初始化和未初始化變量是爲了空間效率,在ELF文件中.bss段不佔據實際的存儲器空間,僅僅是一個佔位符。 - .debug
調試符號表,調試器用此段的信息幫助調試
簡稱sym,包含如下信息:
st_name;
st_value;
st_size;
st_info;
st_other;
st_shndx;函數
- section header table
簡稱Shdr,包含信息:
sh_name; //節區名稱,字符串表索引值
sh_type; //節區種類,如rel*
sh_flags; //
sh_addr; /地址
sh_offset; //輸出節區第一個字節偏移
sh_size; //節區大小
sh_link; //給出字節頭部表索引連接
sh_info; //給出節區附加信息
sh_addralign; //對齊約束
sh_entsize; //給出對於某些有固定項目的大小,如符號表工具
2. elf的內存加載
實際上,編譯後的elf文件的加載在不一樣平臺上的狀況是不同的。
url
- 對於含有文件系統和動態加載功能操做系統的CPU
elf文件會經過某種方式(FTP或者網絡文件系統)被寫入到OS的文件系統。spa
首先先說明一下OS的啓動。對該類型CPU來講,其操做系統kernel已經存儲在硬盤中了,上電後bootloader會對CPU進行初始化,隨後就會將操做系統鏡像加載到SRAM特定的地址,隨後CPU整個的控制權所有移交給kernel。操作系統
OS接管系統後,會進一步初始化並掛載文件系統,此時kernel即可加載文件系統中的elf文件。kernel首先將該文件加載到CPU中的SRAM,完成相應的初始化後將控制權交給應用程序。.net
- 對於簡單操做系統和無操做系統的CPU
該類型的CPU因爲不能提供加載功能,所以在生成elf文件後須要使用二進制處理工具objcopy將elf文件轉換成bin文件,而後經過相應的燒寫工具將該文件寫入flash中。
如有操做系統,則須要將目標程序和OS並在一塊兒編譯和連接,目標程序只做爲操做系統的一個內部函數調用。此狀況下,操做系統的啓動通常不須要單獨的bootloader去加載,在上電完成初始化後就直接跳轉到操做系統的代碼。
- 對於靜態連接的內存加載:
對於以靜態連接形式編譯的程序,因爲其已是一個完整的不依賴於任何其餘東西的可執行程序,能夠直接被執行。 - 對於動態連接的內存加載工做步驟:
loader程序將elf文件讀入內存,而後啓動連接器程序根據elf文件頭的說明,將其所須要的其餘程序段找到讀入內存並裝配在一塊兒(類似段融合,而後從新編排符號表和重定位表,並根據重定位表來作重定位)。裝配完後返回loader程序繼續執行,而後loader直接跳轉到裝配完成的程序中的入口地址處執行。
本文分享 CSDN - KGback。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。