日本免费全黄少妇一区二区三区-高清无码一区二区三区四区-欧美中文字幕日韩在线观看-国产福利诱惑在线网站-国产中文字幕一区在线-亚洲欧美精品日韩一区-久久国产精品国产精品国产-国产精久久久久久一区二区三区-欧美亚洲国产精品久久久久

elf是什么意思 elf是什么意思英語( 三 )


p_offset: 該segment的數(shù)據(jù)在文件中的偏移地址(相對文件頭)p_vaddr: segment數(shù)據(jù)應該加載到進程的虛擬地址p_paddr: segment數(shù)據(jù)應該加載到進程的物理地址(如果對應系統(tǒng)使用的是物理地址)p_filesz: 該segment數(shù)據(jù)在文件中的大小p_memsz: 該segment數(shù)據(jù)在進程內(nèi)存中的大小 。注意需要滿足 p_memsz>=p_filesz ,多出的部分初始化為0,通常作為 .bss 段內(nèi)容p_flags: 進程中該segment的權(quán)限(R/W/X)p_align: 該segment數(shù)據(jù)的對齊,2的整數(shù)次冪 。即要求 p_offset % p_align = p_vaddr。剩下的 p_type 字段,表示該program segment的類型,主要有以下幾種:
PT_NULL: 表示該段未使用PT_LOAD: Loadable Segment , 將文件中的segment內(nèi)容映射到進程內(nèi)存中對應的地址上 。值得一提的是SPEC中說在program header中的多個PT_LOAD地址是按照虛擬地址遞增排序的 。PT_DYNAMIC: 動態(tài)鏈接中用到的段,通常是RW映射,因為需要由 interpreter (ld.so)修復對應的的入口PT_INTERP: 包含interpreter的路徑,見下文PT_HDR: 表示program header table本身 。如果有這個segment的話,必須要在所有可加載的segment之前,并且在文件中不能出現(xiàn)超過 一次。在不同的操作系統(tǒng)中還可能有一些拓展的類型,比如 PT_GNU_STACK 、 PT_GNU_RELRO 等 , 不一而足 。
小結(jié)至此,ELF文件中相關(guān)的字段已經(jīng)介紹完畢,主要組成也就是Section Header Table和Program Header Table兩部分,整體框架相當簡潔 。而ELF中體現(xiàn)拓展性的地方則是在Section和Segment的類型上(s_type和p_type),這兩個字段的類型都是 ElfN_Word ,在32位系統(tǒng)下大小為4字節(jié),也就是說最多可以支持高達 2^32 - 1 種不同的類型!除了上面介紹的常見類型,不同操作系統(tǒng)或者廠商還能定義自己的類型去實現(xiàn)更多復雜的功能 。
程序加載在新版的ELF標準文檔中 , 將ELF的介紹分成了三部分,第一部分介紹ELF文件本身的結(jié)構(gòu),第二部分是處理器相關(guān)的內(nèi)容,第三部分是操作系統(tǒng)相關(guān)的內(nèi)容 。ELF的加載實際上是與操作系統(tǒng)相關(guān)的,不過大部分情況下我們都是在GNU/Linux環(huán)境中運行,因此就以此為例介紹程序的加載流程 。
Linux中分為用戶態(tài)和內(nèi)核態(tài),執(zhí)行ELF文件在用戶態(tài)的表現(xiàn)就是執(zhí)行 execve 系統(tǒng)調(diào)用,隨后陷入內(nèi)核進行處理 。
內(nèi)核空間內(nèi)核空間對execve的處理其實可以單獨用一篇文章去介紹 , 其中涉及到進程的創(chuàng)建、文件資源的處理以及進程權(quán)限的設(shè)置等等 。我們這里主要關(guān)注其中ELF處理相關(guān)的部分即可,實際上內(nèi)核可以識別多種類型的可執(zhí)行文件 , ELF的處理代碼主要在 fs/binfmt_elf.c 中的 load_elf_binary 函數(shù)中 。
對于ELF而言,Linux內(nèi)核所關(guān)心的只有Program Header部分 , 甚至大部分情況下只關(guān)心三種類型的Header,即 PT_LOAD 、 PT_INTERP 和 PT_GNU_STACK。以3.18內(nèi)核為例,load_elf_binary主要有下面操作:
對ELF文件做一些基本檢查,保證 e_phentsize = sizeof(struct elf_phdr) 并且 e_phnum 的個數(shù)在一定范圍內(nèi);循環(huán)查看每一項program header , 如果有PT_INTERP則使用 open_exec 加載進來,并替換原程序的 bprm->buf ;根據(jù) PT_GNU_STACK 段中的flag設(shè)置棧是否可執(zhí)行;使用 flush_old_exec 來更新當前可執(zhí)行文件的所有引用;使用 setup_new_exec 設(shè)置新的可執(zhí)行文件在內(nèi)核中的狀態(tài);setup_arg_pages 在棧上設(shè)置程序調(diào)用參數(shù)的內(nèi)存頁;循環(huán)每一項 PT_LOAD 類型的段,elf_map 映射到對應內(nèi)存頁中 , 初始化BSS;如果存在interpreter,將入口(elf_entry)設(shè)置為interpreter的函數(shù)入口,否則設(shè)置為原ELF的入口地址;install_exec_creds(bprm) 設(shè)置進程權(quán)限等信息;create_elf_tables 添加需要的信息到程序的棧中,比如 ELF auxiliary vector ;設(shè)置 current->mm 對應的字段;從內(nèi)核的處理流程上來看,如果是靜態(tài)鏈接的程序,實際上內(nèi)核返回用戶空間執(zhí)行的就是該程序的入口地址代碼;如果是動態(tài)鏈接的程序 , 內(nèi)核返回用戶空間執(zhí)行的則是interpreter的代碼,并由其加載實際的ELF程序去執(zhí)行 。

推薦閱讀