20135239 益西拉姆 linux內核分析 可執行程序的裝載

益西拉姆 + 原創做品請勿轉載 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 」

week 7 可執行程序的裝載

1.預處理、編譯、連接和目標文件的格式

  • 從c語言到可執行程序的由來過程
  • 可執行文件的建立——預處理、編譯和連接
  • 以helloworld爲例shell

    • -s assembler 彙編
    • gcc -o hello hello.o -m32 是把hello.o連接成可執行文件。
    • ELF格式的文件是怎麼回事?
    • vi hello 是使用共享庫的。
    • static是靜態庫的意思。
    • 靜態連接和動態連接是怎麼回事?
    • 可執行文件的內部是什麼?

2. 目標文件的格式ELF

目標文件及連接

  • 目標文件是什麼樣的?編輯器

    目標文件中的內容至少有編譯後的機器指令代碼、數據。沒錯,除了這些內容之外,目標文件中還包括了連接時所需要的一些信息,好比符號表、調試信息、字符串等。函數

ELF:exectable and linkable format.可執行和可連接的格式。工具

  • 它是文件格式的標準,可執行鏈接格式是UNIX系統實驗室(USL)做爲應用程序二進制接口(Application Binary Interface(ABI)而開發和發佈的。工具接口標準委員會(TIS)選擇了正在發展中的ELF標準做爲工做在32位INTEL體系上不一樣操做系統之間可移植的二進制文件格式。佈局

  • ABI和目標文件格式是怎麼回事?操作系統

    • ABI 又稱目標文件,應用程序二進制接口。二進制兼容的問題。複雜來說就是:命令行

      - 符號修飾標準、變量內層佈局、函數調用方式等這些跟可執行代碼二進制兼容性相關的內容稱爲ABI(Application Binary Interface)。
    • 常見的ABI格式:

ELF( ELF: 可執行鏈接格式 )中的三種目標文件3d

  • 一個可重定位文件保存着代碼和適當的數據,用來和其餘的object文件一塊兒來建立一個可執行文件或者一個共享文件。(**主要是.o文件 **)
  • 一個可執行文件保存着一個用來執行的程序;該文件指出了exec如何來建立程序進程映像。
  • 一個共享object(目標)文件保存着代碼和合適的數據,用來被下面的兩個連接器連接。第一個是連接編輯器,能夠和其餘的可重定位和共享object文件來建立其餘的object。第二個是動態連接器,聯合一個可執行文件和其餘的共享object文件來文件來建立一個進程映像。
  • ELF目標文件的格式: 
  • ELF文件結構描述 
  • ELF文件頭: 如何查看ELF文件的頭部調試

    shiyanlou:Code/ $ readelf -h hellocode

  • 段頭表

    - 目標文件中各節的位置和大小

    - 處於目標文件的末尾

  • 連接:
    • 連接是一個收集、組織程序所需的不一樣代碼 和數據的過程,以便程序能被裝入內存並被執行。
  • 連接過程分爲兩步: - 空間與地址分配: - 掃描全部的輸入目標文件,得到它們的各個段的長度、屬性和位置,而且將輸入目標文件中的符號定義和符號引用收集起來,統一放到一個全局符號表。這一步中,連接器將能得到全部輸入目標文件的段長度,而且將它們合併,計算出輸出文件中各個段合併後的長度與位置,並創建映射關係。 - 符號解析與重定位: - 使用上面第一步中收集到的全部信息,讀取輸入文件中段的數據、重定位信息,而且進行符號解析與重定位、調整代碼中的地址等。事實上第二步是連接過程的核心,特別是重定位過程。

靜態連接的ELF可執行文件與進程的地址空間

目標文件、可執行文件與進程空間

- 通常靜態連接都會將全部代碼放在一個代碼段。 - 動態連接的進程會有多個代碼段。

可執行目標文件及裝入

  • 可執行目標文件與可重定位目標文件格式相似
  • 可執行目標文件的裝入由裝載器完成

典型的ELF可執行目標文件

處理目標文件的一些工具

2.可執行程序、共享庫和動態連接

裝載可執行程序以前的工做。 - 可執行程序的執行環境: - 命令行參數和shell環境,通常咱們執行一個程序的Shell環境,咱們的實驗直接使用execve系統調用。 - $ ls -l /usr/bin 列出/usr/bin下的目錄信息 - Shell自己不限制命令行參數的個數,命令行參數的個數受限於命令自身 - ---例如,int main(int argc, char *argv[]) - ---又如, int main(int argc, char *argv[], char envp[]) - Shell會調用execve將命令行參數和環境參數傳遞給可執行程序的main函數 - ---int execve(const char * filename,char * const argv[ ],char * const envp[ ]); - 庫函數exec都是execve的封裝例程 - - 命令行參數和環境變量是如何保存和傳遞的? - 命令行參數和環境串都放在用戶態堆棧中

- shell程序->>execve->> sys_execve
- 而後在初始化新程序堆棧時拷貝進去
- 先函數調用參數傳遞,在系統調用參數傳遞

裝載時動態連接和運行時動態連接應用舉例

動態連接分爲可執行程序裝載時動態連接和運行時動態連接

3.可執行程序的裝載

可執行程序的裝載相關關鍵問題分析

sysexecve內核處理過程 - sysexecve內部會解析可執行文件格式

  • doexecve -> doexecvecommon -> execbinprm
  • searchbinaryhandler符合尋找文件格式對應的解析模塊,以下(根據文件頭部信息尋找對應的文件格式處理模塊):
  • 下面的地方至關於被觀察者代碼裏面的一部分:
  • 對於ELF格式的可執行文件fmt->loadbinary(bprm);執行的應該是loadelf_binary其內部是和ELF文件格式解析的部分須要和ELF文件格式標準結合起來閱讀
  • Linux內核是如何支持多種不一樣的可執行文件格式的?
  • 下面的屬於觀察者: 
  • ---elfformat 和 initelf_binfmt,這裏是否是就是觀察者模式中的觀察者?(上面有答案。)
  • 可執行文件開始執行的起點在哪裏?如何才能讓execve系統調用返回到用戶態時執行新程序?
  • 修改int 0x80壓入內核堆棧的EIP
  • loadelfbinary -> ** start_thread** 經過修改內核堆棧中EIP的值做爲新程序的起點。

sys_execve的內部處理過程

  • ELF可執行文件會被默認映射到0x8048000這個地址。
  • 須要動態連接的可執行文件先加載連接器ld 
  • 將CPU控制權交給ld來加載依賴庫並完成動態連接。
  • 對於靜態連接庫的文件elf_entry是新程序執行的起點。

使用gdb跟蹤sys_execve內核函數的處理過程

可執行程序的裝載與莊生夢蝶的故事

  • 莊生夢蝶 —— 醒來迷惑是莊周夢見了蝴蝶仍是蝴蝶夢見了莊周?
  • 莊周(調用execve的可執行程序)入睡(調用execve陷入內核),醒來(系統調用execve返回用戶態)發現本身是蝴蝶(被execve加載的可執行程序)

淺析動態連接的可執行程序的裝載

  • 實際上動態連接庫的依賴關係會造成一個圖。
  • 是由內核負責加載可執行程序依賴的動態連接庫嗎?
  • 當一個問件是Interpreter是是依賴的。
  • 動態連接庫的裝載過程是一個圖的遍歷。
  • 裝載和連接以後ld將CPU的控制權交給可執行程序。
相關文章
相關標籤/搜索