可執行程序的裝載——劉世鵬20135304


   可執行程序的裝載

作者:20135304劉世鵬

  《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 

一、預處理、編譯、鏈接和目的文件的格式

1、1可執行程序是怎么得來的

  • C代碼經過編譯器的預處理編譯、編譯成匯編代碼、編譯器將其編譯成目標代碼、鏈接成可執行文件。
  • 預處理負責把include的文件包含進來及宏替換等工作。
  • 預處理之后的文件編譯成匯編代碼。
  • 匯編代碼.s編譯成.o

1、2目標文件格式的ELF

  • 常見的文件格式:A.out(最古老的)、 COFF 、PE(windows系統)、 ELF(Linux系統)
  • ABI應用程序二進制接口,在目標文件中已經是二進制兼容的格式了,目標文件適應到某一種CPU體系結構
  • ELF格式中主要有3種可執行文件:可重定位文件.o,可執行文件,共享目標文件

  • 一個ELF頭在文件的開始,保存了路線圖,描述了文件的組織情況
  • 當創建或增加一個進程映像的時候,系統在理論上將拷貝一個文件的段到一個虛擬的內存段

1、3靜態鏈接的ELF可執行文件和進程的地址空間

  • 可執行文件ELF加載到內存中去:代碼的數據加載到內存中去
  • 默認ELF文件加載到0x8048000
  • 程序的實際入口0x8048300(啟動一個剛加載過可執行文件之后開始執行的入口點)
  • 一般靜態鏈接會將所有代碼放在一個代碼段
  • 動態鏈接的進程會有多個代碼段

二、可執行程序、共享庫和動態鏈接

2、1裝載可執行程序之前的動作

  • 可執行程序的執行環境:shell命令行、main函數的參數和execve參數
  • shell本身不限制命令行參數的個數,命令行參數的個數受限於命令本身
  • shell會調用execve將命令行參數和環境傳遞給可執行程序的main函數
  • 命令行參數和環境變量是如何保存和傳遞的:execve將原來的執行環境覆蓋掉了,shell程序——>execve——>sys_execve然后在初始化新程序堆棧時拷貝進去
  • 先函數調用參數傳遞,再系統調用參數傳遞

2、2裝載動態鏈接和運行時動態鏈接應用舉例

  • 動態鏈接分為:可執行程序裝載時動態鏈接和運行時動態鏈接
  • 准備.so文件——>編譯成libshlbexample.so文件(共享庫)——>編譯成libdllibexample.so文件(動態裝載)
  • 編譯main:只提供了shellexample的-L和-l,並沒有提供dllibexample的相關信息,只指明了-ldl

三、可執行程序的裝載

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

  • execve和fork都是特殊的系統的調用,當前程序執行到execve系統調用時陷入到內核態,execve加載可執行文件把當前進程的可執行文件覆蓋掉,execve返回新的可執行程序的執行起點。

  • int execve(把命令行和環境參數加載進來)
  • sys_execve內部會解析可執行文件格式:do_execve->do_execve_common->exec_binprm
  • search_binaty_handle符合文件格式,對應的解析模塊(根據文件頭部信息尋找對應的文件格式處理模塊)
  • 對於ELF格式的可執行文件執行的是load_elf_binary

  • elf_format和init_elf_binfnt是觀察者模式中的觀察者
  • 尋找頭文件是被觀察者,出現elf格式文件,觀察者自動執行elf_format模塊
  • execve系統調用返回用戶態從哪里開始執行:load_elf_binary->start_thread(通過修改內核堆棧中EIP的值作為新程序的起點)

3、2sys_execve的內部處理過程

  • search_binary_handler(尋找可執行文件的處理函數) fmt->load_binary(加載可執行程序的處理函數)
  • register_binfmt(注冊結構體變量)
  • kernal_read讀取文件信息
  • ELF可執行文件會被默認映射到0x8048000這個地址
  • 需要動態鏈接的可執行文件先加載連接器ld這個共享庫 load_elf_interp(加載動態連接器的起點)
  • 如果是靜態鏈接直接進入elf_entry,elf_entry是新程序的起點
  • start_thread(如果是靜態鏈接,直接指向main8048000;如果可執行文件是動態鏈接庫,指向動態連接器的起點

3、3使用gdb跟蹤sys_execve的內部處理過程

自己實驗截圖:

(1)克隆,覆蓋test.c

test.c文件代碼:

(2)生成根文件系統時,將init hello放入rootfs地址中,這樣在執行exec文件時,就自動加載hello文件

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

1、加載符號表,並連接到端口1234

2、設置斷點:b sys_execve(可以先停在sys_execve然后再設置其他斷點),b load_elf_binary,b start_thread。

3、執行

4、輸入c繼續執行,輸入指令exec,list查看,按s可以跟蹤進行到do_execve的內部。

3、4可執行程序的裝載與庄生夢蝶的故事

  • 庄周(調用execve的可執行程序)
  • 入睡(調用execve陷入內核)
  • 醒來(系統調用execve返回用戶態)
  • 發現自己是蝴蝶(被execve加載的可執行程序)

3、5淺析動態鏈接的可執行程序裝載

  •  動態鏈接的過程,內核做了什么?動態鏈接庫的依賴會形成一個圖
  • ELF格式中的,.interp和.dynamic需要依賴動態鏈接器來解析

  • entry返回到用戶態時不是返回到可執行程序規定的起點,返回到動態鏈接器的程序入口

  •  裝載和鏈接之后ld將CPU的控制權交給可執行程序

  • 動態鏈接庫的裝載過程是一個圖的遍歷過程

四、總結

1、可執行程序的產生:

C語言代碼-->編譯器預處理-->編譯成匯編代碼-->匯編器編譯成目標代碼-->鏈接成可執行文件,再由操作系統加載到內存中執行。

2、ELF格式中主要有3種可執行文件:可重定位文件.o,可執行文件,共享目標文件。

3、ELF可執行文件會被默認映射到0x8048000這個地址。

4、命令行參數和環境變量是如何進入新程序的堆棧的?

Shell程序-->execve-->sys_execve,然后在初始化新程序堆棧時拷貝進去。

先函數調用參數傳遞,再系統調用參數傳遞。

5、當前程序執行到execve系統調用時陷入內核態,在內核中用execve加載可執行文件,把當前進程的可執行文件覆蓋掉,execve系統調用返回到新的可執行程序的起點。

6、動態鏈接庫的裝載過程是一個圖的遍歷過程,

ELF格式中的.interp和.dynamic需要依賴動態鏈接器來解析,entry返回到用戶態時不是返回到可執行程序規定的起點,返回到動態鏈接器的程序入口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM