ELF檔案在帶載入器的OS中和裸奔的載入及執行

2021-06-08 01:49:03 字數 2505 閱讀 1793

作者:lelee007

工作關係,這個周花了一天時間好好研究了以下elf檔案及可執行elf檔案的載入。中間過程可謂收穫不小,呵呵,因為之前搞linux驅動、arm裸奔始終沒有認真研究過elf檔案,這次深入學習一下,把之前很多沒弄清的原理基本摸清楚了。

首先簡單說明一下elf檔案的用途(呵呵,昨天講解的時候直奔elf的細節,結果被pl bs,說俺這樣講別人沒做這塊的根本不知道在講什麼,所以今天。。。),elf檔案一種unix檔案格式,全稱是executable and linkable format,即可執行鏈結格式,在unix系統及linux、bsd等類unix系統中廣泛使用。這種檔案格式主要作為鏈結目標檔案用。elf格式檔案實際上有3類,可重定位檔案、可執行檔案、共享目標庫檔案。這三種檔案用途不同,內部結構略有差別。可執行檔案是由程式段(segment)構成,每個段由乙個段描述項來描述該段的相關資訊,比如該段在elf檔案內的偏移位址、該段的型別、該段在執行時的載入位址、該段的大小等等,所有段的描述項構成乙個結構體陣列,即程式段描述表,有些地方也叫程式頭描述表,該錶在elf檔案中的位置是在elf檔案頭之後,而程式的各個段在elf檔案中則是緊接這程式段描述表之後。可重定位檔案則是由節區(section)構成,與可執行檔案的程式段類似,每個節區也有乙個節區描述項,所有的節區描述項也構成乙個陣列。可重定位檔案與可執行檔案在結構上稍微有些區別,就是節區描述表是放在節區後面的,即在elf檔案內部是接著節區之後的,而不是像可執行檔案中的程式段描述表那樣放在程式段之前。另外可執行檔案和可重定位檔案的乙個重要區別就是,可執行檔案中,節區描述表是可選的,並非必須,實際情況中一般是不用節區描述表的;可重定位檔案中,程式段描述表也是可選的,而非必須,同樣實際情況中一般不用程式段描述表。至於這兩種檔案中對應的描述表如果不存在,則在elf檔案頭中將對應成員設為0來表示。最後,共享目標庫檔案則是綜合前面兩種檔案,段內分節區,段描述表和節區描述表都有!

介紹完elf的大致結構之後,針對可執行elf檔案介紹一下該類檔案中的幾個比較重要的資訊及相互之間的關係(下面所有介紹全部針對可執行檔案)。elf檔案頭可以用elf32_ehdr結構體來描述,該結構體具體資訊不再羅嗦,網上隨便找一下一大把介紹的,只介紹其中幾個比較關鍵的成員。

首先是e_entry,這個成員描述的是可執行檔案載入到記憶體中以後機器可執行的程式的入口位址!關於該程式還是羅嗦一下,因為她真的真的灰常灰常的重要!!!首先,e_enty的值是乙個位址,指向記憶體中的乙個單元;其次,e_entry指向的記憶體單元是儲存cpu執行該elf檔案時執行的第一條指令的。簡單說就是乙個程式源**中無論如何都會有乙個唯一的入口,一般情況下,在有os的情形下,對應c程式中的main,而在裸奔的情況下,一般都會用乙個_start來指定程式的入口,這些標示符在源**被鏈結成可執行檔案並被載入到記憶體中之後,都會有乙個明確的位址,cpu從該位址而且僅能從該位址開始執行這個程式才能正確執行,這個位址在鏈結成elf檔案時就被聯結器寫到elf檔案頭中的e_entry成員中了,cpu正是通過e_entry才知道程式載入到記憶體之後該從什麼位址(cpu是不認識程式符號的,比如main,_start之類的,cpu只知道位址)開始執行這個程式。

其次是e_poff,該成員標明了在elf檔案中,程式段描述表在elf檔案中的偏移。不羅嗦,因為必須要知道程式段描述表的位置,而通過e_phoff便可知道。

再次就是e_phentsize和e_phnum啦。對於elf檔案,每個程式段描述項的大小是一致的,因此之用乙個成員來表示程式段描述項大小便可,不用每個描述項的大小都用乙個成員來描述,e_phentsize正是用來描述描述項大小的。e_phnum則是描述程式段描述項個數的,即程式段描述表中表項的個數,重複一點,有幾個描述項就表明elf檔案中有幾個程式段。

接下來介紹上面說的程式段描述項。顧名思義,程式段描述項是描述程式段的,一點也不假!可執行程式中一般都會有.text,.data,.bss這些段,一般情況下是這樣,但是不排除例外,比如還有.stack或者其他一些程式猿自定義段之類的,甚至有時僅僅只有乙個.text段,不存在其他任何段也是可以滴。這些段在讓cpu能執行前都需要先正確的載入到記憶體中去,這就需要相當多的資訊才可以保證載入的正確性了,比如乙個段要載入到記憶體的什麼位置啊(p_vaddr或者p_paddr),引導程式從elf的神馬位置開始讀取該段資料啊(p_poff),讀取多少資料到記憶體中去啊(p_filesz和p_memsz)。

到這裡已經差不多把elf可執行檔案的主要資訊交代了,最後再羅嗦以下e_entry和入口所在段的p_vaddr(或者p_paddr)的關係吧。不知道是不是也會有人在開始有同我一樣的疑惑,就是這倆成員的關係,能否替換使用!因為開始我一直yy可執行段開始存放的就是機器碼,即可執行的第一條機器碼就放在段的開始位置,於是俺就繼續yy,那這個段載入到記憶體的位址p_vaddr就應該是和e_entry是一樣的啦,而且無論何時都應該是一樣的啦!於是乎還到處找資料,甚至上網所有相關資訊來確認俺的yy想法!結果搜到乙個僅僅簡單介紹了一下p_vaddr <= e_entry < p_vaddr + p_filesz,當時看到這個真是蛋疼的緊!不明白那個<=中的《是何種情形下才成立!後來想了好久,冥冥之中才意識到segment的開頭也是有可能會插播一下訊息或者廣告之類的東東,然後才接第一條機器碼,如此以後e_entry便不會等於p_vaddr了,而是會稍微大一點點,至此方幡然醒悟!

ELF檔案的格式和載入過程

一 elf 檔案的格式 elf 檔案型別 1 可重定位檔案 o 目標檔案 用於鏈結建立可執行檔案或 so 檔案 2 可執行檔案 用於執行 3 so 共享物件 檔案 用於鏈結 注 乙個 program header 對應乙個 segment 乙個 section header 對應乙個 section...

ELF檔案的格式和載入過程

一 elf 檔案的格式 elf 檔案型別 1 可重定位檔案 o 目標檔案 用於鏈結建立可執行檔案或 so 檔案 2 可執行檔案 用於執行 3 so 共享物件 檔案 用於鏈結 注 乙個 program header 對應乙個 segment 乙個 section header 對應乙個 section...

「在Web 窗體設計器中未能載入該檔案」的解決方法

用visual studio.net2003開啟原來寫的乙個asp.net程式,當開啟其中的某個檔案時,我在裡面使用了使用者自定的控制項,總出現下面的提示錯誤,不能顯示介面設計介面,但能夠編譯。錯誤提示如下 檔案中的類都不能進行設計,因此未能為該檔案顯示設計器。設計器檢查出檔案中有以下類 rcatg...