文章目錄
以下內容為<<linux核心編程>>筆記
連結程式
找出所有引用的外部模組並連結起來,這些外部模組或函數庫一般來自於開發人員,作業系統和C運行庫。
連結程式取出這些函數庫,修訂指標位置(重定位),並交叉引用模組中的符號解析,最終產生一個可執行模組。符號可以是全域的也可以是局部的。全域符號可以在模組內部定義,或由另一模組外部參考。
靜態庫是在連結時被找到並複製的,而動態庫和共用庫是在運行時才裝載的,並讓所有的進程共用。linux提供的系統調用dlopen(),dlsym(),dlclose(),用於載入/開啟共用庫,尋找庫中的符號,然後關閉共用庫
ELF二進位目標檔案
可執行ELF目標檔案包括:ELF頭,程式頭表(用於載入的節),第1節,第2節。。。。節頭表(可選)
1.ELF檔案頭
typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; //標識該檔案是否為ELF檔案 Elf32_Half e_type; //指定目標檔案類型,例如可執行檔,重定位檔案,共用的目標檔案 Elf32_Half e_machine; //被編譯檔案所在系統的體繫結構 Elf32_Word e_version; //目標檔案的版本 Elf32_Addr e_entry; /* Entry point */ //程式的起始地址 Elf32_Off e_phoff; //儲存程式頭表在檔案中的位移量 Elf32_Off e_shoff; //儲存節頭表在檔案中的位移量 Elf32_Word e_flags; //儲存於特定與處理器的標誌 Elf32_Half e_ehsize; //欄位儲存ELF頭的大小 Elf32_Half e_phentsize; //儲存程式頭表中的每一項的大小 Elf32_Half e_phnum; //程式頭中表項的個數 Elf32_Half e_shentsize; //節頭表中每一項的大小 Elf32_Half e_shnum; //儲存節頭中項的數量,表明該檔案中有多少節 Elf32_Half e_shstrndx; //儲存節頭中節字串的索引} Elf32_Ehdr;2 節頭表
typedef struct elf32_shdr { Elf32_Word sh_name; //包含節名 Elf32_Word sh_type; //包含節的內容 Elf32_Word sh_flags; //各種屬性的內容 Elf32_Addr sh_addr; //節在記憶體映像中的地址 Elf32_Off sh_offset; //儲存ELF檔案中這一節中初始位元組的位移量 Elf32_Word sh_size; //包含節的大小 Elf32_Word sh_link; //錶鏈接的索引 Elf32_Word sh_info; //包含附加資訊 Elf32_Word sh_addralign; //包含地址對其的約束 Elf32_Word sh_entsize; //節中每項的大小} Elf32_Shdr;
3 非可執行ELF檔案的節bss 為初始化的資料.data 已初始化的資料.hash 符號散列表.init 初始化代碼.symtab 符號表.text 可執行檔指令.plt 過程連結資料表.rodata 唯讀資料.dynamic 動態連結資訊等等4 程式頭表
typedef struct elf64_phdr { Elf64_Word p_type; //描述該段的類型 Elf64_Word p_flags; //以p_type而定 Elf64_Off p_offset; //該段的開始相對於檔案開始的位移量 Elf64_Addr p_vaddr; //段虛擬位址 Elf64_Addr p_paddr; //段的虛擬位址 Elf64_Xword p_filesz; //檔案映像中該段的位元組數 Elf64_Xword p_memsz; //記憶體映像中該段的位元組數 Elf64_Xword p_align; //描述要對齊的段在記憶體中如何對齊,該值是2的整數次冪
} Elf64_Phdr;
通過這些資訊,系統函數exec()和連結程式合作,為可執行程式在記憶體中建立進程映像,該過程如下:
1. 將可執行檔的段加入記憶體2. 載入所有需要的共用庫3. 需要時重新導向可執行檔及其共用對象4. 將控制權交給程式