安大大 + 原創作品轉載請注明出處 + 《Linux操作系統分析》MOOC課程
知識要點
1 可執行程序是怎么得來的
對于c代碼來說,先是經過編譯器的預處理,然后編譯成匯編代碼。再由匯編器把匯編代碼編譯成目標代碼,然后再連接成可執行文件。可執行文件由操作系統加載到內存里執行。
shiyanlou:~/ $ cd Code
shiyanlou:Code/ $ vi hello.c
shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32 #對c程序預處理,hello.cpp是預處理的中間文件
shiyanlou:Code/ $ vi hello.cpp
shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32 #編譯成匯編代碼
shiyanlou:Code/ $ vi hello.s
shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32 #編譯成目標代碼
shiyanlou:Code/ $ vi hello.o #二進制文件,當中已經有一些機器指令
shiyanlou:Code/ $ gcc -o hello hello.o -m32 #連接成可執行程序
shiyanlou:Code/ $ vi hello #hello.o和hello 都是ELF格式的文件
shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static #把所有依賴的內容都放在了程序的內部
shiyanlou:Code/ $ ls -l
-rwxrwxr-x 1 shiyanlou shiyanlou 7292 3\u6708 23 09:39 hello
-rw-rw-r-- 1 shiyanlou shiyanlou 64 3\u6708 23 09:30 hello.c
-rw-rw-r-- 1 shiyanlou shiyanlou 17302 3\u6708 23 09:35 hello.cpp
-rw-rw-r-- 1 shiyanlou shiyanlou 1020 3\u6708 23 09:38 hello.o
-rw-rw-r-- 1 shiyanlou shiyanlou 470 3\u6708 23 09:35 hello.s
-rwxrwxr-x 1 shiyanlou shiyanlou 733254 3\u6708 23 09:41 hello.static #比hello大很多
2 目標文件的格式,
.o文件和可執行文件都是目標文件。
ELF(Executable and Linkable Format)可執行與可鏈接格式,是一個文件格式的標準。在目標文件里邊已經是二進制兼容的格式,即這個目標文件已經適應到某種CPU體系結構上的二進制指令(ABI)。
3 在ELF當中有三種主要的目標文件
- 一個可重定位(relocatable)文件(主要是.o文件)保存著代碼和適當的數據,用來和其他的object文件一起來創建一個可執行文件或者是一個共享文件。
- 一個可執行(executable)文件保存著一個用來執行的程序;該文件指出了 exec(BA_OS)如何來創建程序進程映像。
- 一個共享object文件(主要是.so文件)保存著代碼和合適的數據,用來被下面的兩個連接器鏈接。第一個是連接編輯器(靜態鏈接)[參看ld(SD_CMD)],可以和其他的重定位和共享object文件來創建其他的object。第二個是動態鏈接器,聯合一個可執行文件和其他的共享object文件來創建一個進程映象。
4 目標文件的格式ELF
Object文件參與程序的聯接(創建一個程序)和程序的執行(運行一個程序)。
object 文件格式提供了一個方便有效的方法并行的視角看待文件的內容,
在他們的活動中,反映出不同的需要。
Linking 視角 Execution 視角
============ ==============
ELF header ELF header
Program header table (optional) Program header table
Section 1 Segment 1
... Segment 2
Section n ...
Section header table Section header table (optional)
一個ELF頭在文件的開始,保存了路線圖(road map),描述了該文件的組織情況。程序頭表(program header table)告訴系統如何來創建一個進程的內存映象。section頭表(section header table)包含了描述文件sections的信息。每個section在這個表中有一個入口;每個入口給出了該section的名字,大小,等等信息。
Entry point address是程序的起點
可執行文件的格式和進程的地址空間有一個映射關系,
可執行程序加載的主要工作。
當創建或增加一個進程映像的時候,系統在理論上將拷貝一個文件的段到一個虛擬的內存段
+ Figure 2-5: Executable File
File Offset File Virtual Address
=========== ==== ===============
0 ELF header
Program header table
Other information
0x100 Text segment 0x8048100
...
0x2be00 bytes 0x8073eff
0x2bf00 Data segment 0x8074f00
...
0x4e00 bytes 0x8079cff
0x30d00 Other information
...
參考:ELF文件格式(中文) 英文
5 靜態鏈接的ELF可執行文件與進程的地址空間
Entry point address 是可執行文件加載到內存中開始執行的第一行代碼
一般靜態鏈接會將所有代碼放在一個代碼段
動態鏈接的進程會有多個代碼段
6裝載可執行程序之前的工作
命令行參數和環境變量是如何保存和傳遞的
調用execve系統調用時,要加載的可執行程序,把原來的進程環境覆蓋掉,覆蓋掉之后,用戶態堆棧被清空。
命令行參數和環境變量是如何進入新進程的堆棧的
創建一個新的用戶態堆棧時,把命令行參數的內容和環境變量的內容,通過指針的方式傳遞到系統調用的內核處理函數。內核處理函數在創建一個新的可執行程序的用戶態堆棧時,會把argv和envp拷貝到用戶態堆棧里,來初始化新的可執行程序執行的上下文環境。
先函數調用參數傳遞,再系統調用參數傳遞。
7
動態鏈接分為可執行程序裝載時動態鏈接和運行時動態鏈接
linux下動態鏈接文件.so,windows是dll
裝載可執行程序之前的工作
總結
把ELF可執行文件加載到內存中,通過ELF頭部的信息,找到程序的入口執行。