Linux系統下的ELF檔案格式

2021-03-03 21:35:45 字數 4740 閱讀 7790

1 引言

elf(executable and linkable format)即可執行連線檔案格式,是linux,svr4和solaris2.0預設的目標檔案格式,目前標準介面委員會tis已將elf標準化為一種可移植的目標檔案格式,執行於32-bit intel體系微機上,可與多種作業系統相容。分析elf檔案有助於理解一些重要的系統概念,例如程式的編譯和鏈結,程式的載入和執行等

2 elf檔案格式

2.1 elf檔案的型別

elf檔案主要有三種型別:

(1)可重定位檔案包含了**和資料.可與其它elf檔案建立乙個可執行或共享的檔案:

(2)可執行檔案時可直接執行的程式:

(3)共享目標檔案包括**和資料,可以在兩個地方鏈結。第一,聯結器可以把它和其它可重定位檔案和共享檔案一起處理以建立另乙個elf檔案;第二,動態鏈結器把它和乙個可執行檔案和其它共享檔案結合在一起建立乙個程序映像。

2.2 elf檔案的組織

elf檔案參與程式的連線(建立乙個程式)和程式的執行(執行乙個程式),編譯器和鏈結器將其視為節頭表(section header table)描述的一些節(section)的集合,而載入器則將其視為程式頭表(program header table)描述的段(segment)的集合,通常乙個段可以包含多個節。可重定位檔案都包含乙個節頭表,可執行檔案都包含乙個程式頭表。共享檔案兩者都包含有。

為此,elf檔案格式同時提供了兩種看待檔案內容的方式,反映了不同行為的不同要求。下圖顯示了elf檔案的組織。

2.3 檔案頭(elf header)

elf頭在程式的開始部位,作為引路表描述整個elf的檔案結構,其資訊大致分為四部分:一是系統相關資訊,二是目標檔案型別,三是載入相關資訊,四是鏈結相關資訊其中系統相關資訊包括elf檔案魔數(標識elf檔案),平台位數,資料編碼方式,elf頭部版本,硬體平台e_machine,目標檔案版本e_version,處理器特定標誌e_ftags:這些資訊的引入極大增強了elf檔案的可移植性,使交叉編譯成為可能。

目標檔案型別用e_type的值表示,可重定位檔案為1,可執行檔案為2,共享檔案為3;載入相關資訊有:程式進入點e_entry.程式頭表偏移量e_phoff,elf頭部長度e_ehsize,程式頭表中乙個條目的長度e_phentsize,程式頭表條目數目e_phnum;鏈結相關資訊有:節頭表偏移量e_shoff,節頭表中乙個條目的長度e_shentsize,節頭表條目個數e_shnum ,節頭表字元索引e shs***x。

可使用readelf -h filename來察看檔案頭的內容。

檔案頭的資料結構如下:

typedef struct elf32_hdrelf32_ehdr;

2.4 程式頭表(program header table)

程式頭表告訴系統如何建立乙個程序映像.它是從載入執行的角度來看待elf檔案.從它的角度看.elf檔案被分成許多段,elf檔案中的**、鏈結資訊和注釋都以段的形式存放。每個段都在程式頭表中有乙個表項描述,包含以下屬性:段的型別,段的駐留位置相對於檔案開始處的偏移,段在記憶體中的首位元組位址,段的實體地址,段在檔案映像中的位元組數.段在記憶體映像中的位元組數,段在記憶體和檔案中的對齊標記。

可用readelf -l filename察看程式頭表中的內容。程式頭表的結構如下:

typedef struct elf32_phdrelf32_shdr;

3 elf的特性

3.1平台相關

在elf 檔案頭中包含了足夠的平台相關資訊,如資料編碼方式,平台位數,硬體平台e_machine等,這些平台相關資訊可在編譯由編譯器決定。例如,與平台位數的相關的資料結構的定義在elf.h的標頭檔案中.在編譯預處理時確定:

#if elf class==elfclass32

extern elf32_dyn_dynamic;

#define elfhdr elf32_hdr;

#define elf_phdr elf32_phdr;

#define elf_note elf32_note;

#else

extern elf64_dyn_dynamic;

#define elfhdr elf64_hdr;

#define elf_phdr elf64_phdr;

#define elf_note elf64_note;

#endif

linux系統載入elf可執行檔案時,必須首先做一些簡單的一致性檢查.其**如下

if(memcmp(elf_ex.e_ident,elfmag,selfmag)!=0)

goto out; //檢查檔案頭開始四個字元是否為elf魔數'\0177elf

if(elf_ex.e_type!=et_exec&&elf_ex.e_type!=et_dyn)

goto out;//檢查檔案型別是否為可執行檔案或共享目標檔案

if(!elf_check_arch(&elf_ex))

goto out;//檢查硬體平台是否一致

其中的elf_check_arch(x)在不同的硬體平台上有不同的定義,其由系統的硬體平台決定。這樣,在硬體平台相同的系統上,elf可以不作修改的執行。因此,它可以支援不同平台上的交叉編譯(cross_***pilation)和交叉鏈結(cross_linking)。

3.2 pic

elf可以生成一種特殊的**——與位置無關的**(position-independent code,pic)。使用者對gcc使用-fpic指示gnu編譯系統生成pic**。它是實現共享庫或共享可執行**的基礎.這種**的特殊性在於它可以載入到記憶體位址空間的任何位址執行.這也是載入器可以很方便的在程序中動態鏈結共享庫。

pic的實現運用了乙個事實,。因此,編譯器在資料段開始的地方建立了乙個表.叫做全域性偏移量表(global offset table.got)。got包含每個被這個目標模組引用的全域性資料目標的表目。

編譯器還為got中每個表目生成乙個重定位記錄。在載入時,動態鏈結器會重定位got中的每個表目,使得它包含正確的絕對位址。pic**在**中實現通過got間接的引用每個全域性變數,這樣,**中本來簡單的資料引用就變得複雜,必須加入得到got適當表目內容的指令。

對唯讀資料的引用也根據同樣的道理,所以,加上 ic編譯成的**比一般的**開銷大。

如果乙個elf可執行檔案需要呼叫定義在共享庫中的任何函式,那麼它就有自己的got和plt(procedure linkage table,過程鏈結表).這兩個節之間的互動可以實現延遲繫結(lazy binging),這種方法將過程位址的繫結推遲到第一次呼叫該函式。為了實現延遲繫結,got的頭三條表目是特殊的:got[0]包含.

dynamic段的位址,.dynamic段包含了動態鏈結器用來繫結過程位址的資訊,比如符號的位置和重定位資訊;got[1]包含動態鏈結器的標識;got[2]包含動態鏈結器的延遲繫結**的入口點。got的其他表目為本模組要引用的乙個全域性變數或函式的位址。

plt是乙個以16位元組(32位平台中)表目的陣列形式出現的**序列。其中plt[0]是乙個特殊的表目,它跳轉到動態鏈結器中執行;每個定義在共享庫中並被本模組呼叫的函式在plt中都有乙個表目,從plt[1]開始.模組對函式的呼叫會轉到相應plt表目中執行,這些表目由三條指令構成。第一條指令是跳轉到相應的got儲存的位址值中.第二條指令把函式相應的id壓入棧中,第三條指令跳轉到plt[o]中呼叫動態鏈結器解析函式位址,並把函式真正位址存入相應的got表目中。

被呼叫函式got相應表目中儲存的最初位址為相應plt表目中第二條指令的位址值,函式第一次被呼叫後.got表目中的值就為函式的真正位址。因此,第一次呼叫函式時開銷比較大.但是其後的每次呼叫都只會花費一條指令和乙個間接的儲存器引用。

3.3 強大的工具支援

由於gnu由大量的工具支援elf檔案個時. 隨著gnu工具的功能的擴充套件.程式設計師對elf檔案的運用也越來越靈活。例如,在c++中全域性的建構函式和析構函式必須非常小心的處理碰到的語言規範問題。建構函式必須在main函式之前被呼叫。

析構函式必須在main函式返回之後被呼叫。elf檔案格式中,定義了兩個特殊的節(section),.init和.

fini,.init儲存著可執行指令,它構成了程序的初始化**。當乙個程式開始執行時,在main函式被呼叫之前(c語言稱為main),系統安排執行這個section的中的**。.

fini儲存著可執行指令,它構成了程序的終止**。當乙個程式正常退出時.系統安排執行這個section的中的**。c++編譯器利用這個特性.構造正確的.

init和.fini sections.並結合.ctors(該section儲存著程式的全域性的建構函式的指標陣列)和.

dtors(該section儲存著程式的全域性的析構函式的指標陣列)兩個section,完成全域性的建構函式和析構函式的處理。

gcc還有許多擴充套件的特性.有些對elf 特別的有用。其中乙個就是_attribute_ 。使用_attribute_可以使乙個函式放到_ctor_list_或者_dtor_list_裡。

_attribute_((constructor))促使函式在進入main之前會被自動呼叫。_attribute_((destructor))促使函式在main返回或者exit呼叫之後被自動呼叫。這種函式必須是不能帶引數的而且必須是static void型別的函式。

在elf下,這個特性在一般的可執行檔案和共享庫中都能很好的工作。另外乙個gcc的特性是attribute_(section("sectionname")),使用這個,能把乙個函式或者是資料結構放到任何的section中。

4 結論

elf檔案格式是一種比較複雜的檔案格式,但其應用廣泛。與linux下的其他可執行檔案(a.out,cof)相比,它對節的定義和gnu工具鏈對它的支援使它十分靈活,它儲存的足夠了系統相關資訊使它能支援不同平台上的交叉編譯和交叉鏈結,可移植性很強.同時它在執行中支援動態鏈結共享庫。

Linux檔案系統與磁碟管理

實驗報告 掌握linux下檔案系統的建立 掛載與解除安裝。掌握檔案系統的自動掛載。某企業的linux伺服器中新增了一塊硬碟 dev sdb,請使用fdisk命令新建 dev sdb1主分割槽和 dev sdb2擴充套件分割槽,並在擴充套件分割槽中新建邏輯分割槽 dev sdb5,並使用mkfs命令分...

Linux面試經常問的檔案系統操作命令

1.cat 可以顯示檔案的內容 經常和more搭配使用 或將多個檔案合併成乙個檔案。2.chgrp 用來改變檔案或目錄所屬的使用者組,命令的引數以空格分開的要改變屬組的檔案列表,檔名支援萬用字元,如果使用者不是該檔案的所有者,則不能改變該檔案的所屬組。3.chmod 用於改變檔案或目錄的訪問許可權,...

Linux檔案系統與磁碟管理LVM

硬碟的結構與分割槽 磁頭header,磁軌 track 磁柱 cylinder 扇區 sector 節 分割槽 partition 指定從哪個磁柱 起始磁柱 到哪個磁柱 結束磁柱 的範圍儲存以何種檔案系統儲存 mbr master booter recorder 檔案系統 邏輯塊 block 分割槽...