一、 軟件執(zhí)行流程
1、 軟件編譯流程
? 預(yù)編譯完成宏展開(kāi)工作。
? 為每一個(gè) .cxx 源文件編譯一個(gè)目標(biāo)文件( .obj,.o ),目標(biāo)文件中至少包含二進(jìn)制的代碼段和數(shù)據(jù)段。在 cxx 源文件中可能會(huì)引用在其他 cxx/hxx 中定義的符號(hào),也可能是自己定義的一些符號(hào),這些作用域超過(guò)一個(gè) cxx 文件的符號(hào)稱(chēng)為“ public 符號(hào)”(例如非靜態(tài)函數(shù))。因此每一個(gè)目標(biāo)文件中也包含一個(gè)符號(hào)表,用于記錄自己引用的符號(hào)及自己提供的 public 符號(hào)。
? 編譯器合成這些目標(biāo)文件成一個(gè)庫(kù)文件( .lib ),同時(shí)解析可以找到的符號(hào)引用。此時(shí)這個(gè)庫(kù)文件包含了二進(jìn)制的代碼段和數(shù)據(jù)段,同樣也會(huì)包含一個(gè)符號(hào)表,因?yàn)橛幸恍┓?hào)需要引用其他靜態(tài) / 動(dòng)態(tài)鏈接庫(kù)的導(dǎo)出符號(hào)。
? 鏈接器負(fù)責(zé)把目標(biāo)的庫(kù)文件和所有需要引用的靜態(tài) / 動(dòng)態(tài)鏈接庫(kù)進(jìn)行鏈接,即需要首先把靜態(tài)庫(kù)合成到可執(zhí)行文件中。轉(zhuǎn)換相應(yīng)的符號(hào)引用為地址,然后確保所引用的其他動(dòng)態(tài)鏈接庫(kù)的符號(hào)存在。最后生成可執(zhí)行文件,可執(zhí)行文件的符號(hào)表只需要記錄導(dǎo)入符號(hào)表。
2、 軟件運(yùn)行流程
? 當(dāng)雙擊 App.exe 圖標(biāo)啟動(dòng)程序時(shí),執(zhí)行起來(lái)的 App 進(jìn)程是 shell 調(diào)用 CreateProcess 激活的。 桌面上的帶有小箭頭的快捷方式 (shortcut) 就是一個(gè) shell 鏈接, shell 負(fù)責(zé)管理一個(gè)叫 " 名字空間 " 的類(lèi)似文件系統(tǒng)似的“超文件系統(tǒng)” , 它允許應(yīng)用程序在任何地方在不知訪(fǎng)問(wèn)對(duì)象名字和位置的前提下訪(fǎng)問(wèn)到這個(gè)對(duì)象,此類(lèi)對(duì)象有:文件,目錄,驅(qū)動(dòng)器,打印機(jī)以及網(wǎng)絡(luò)資源。而名字空間就是 shell 把這些對(duì)象有層次組織起來(lái)的一個(gè)結(jié)構(gòu)。名字空間為用戶(hù)和應(yīng)用程序提供了一種可靠和高效的方法來(lái)訪(fǎng)問(wèn)和管理對(duì)象。
? 當(dāng) CreateProcess 函數(shù)被調(diào)用,系統(tǒng)創(chuàng)建一個(gè)“進(jìn)程內(nèi)核對(duì)象”。進(jìn)程內(nèi)核對(duì)象可以看作一個(gè)操作系統(tǒng)用來(lái)管理進(jìn)程的內(nèi)核對(duì)象,它是系統(tǒng)用來(lái)存放關(guān)于進(jìn)程統(tǒng)計(jì)信息的地方(一個(gè)小的數(shù)據(jù)結(jié)構(gòu)),真正創(chuàng)建者是 NtCreateProcess 的系統(tǒng)服務(wù)函數(shù) ( 也叫執(zhí)行體服務(wù)函數(shù) ) ,他創(chuàng)建了進(jìn)程內(nèi)核對(duì)象供用戶(hù)擴(kuò)展。進(jìn)程內(nèi)核對(duì)象的初始使用計(jì)數(shù)為 1 。然后系統(tǒng)為該進(jìn)程創(chuàng)建 4GB ( =2^32) 的虛擬地址空間 ( 所謂虛擬就不是真的創(chuàng)建 4GB 的物理內(nèi)存空間,這些空間不是真在物理內(nèi)存上 ). 用于加載 App.exe 可執(zhí)行文件和任何必要的 dll 文件的數(shù)據(jù)和代碼。 系統(tǒng)為該進(jìn)程創(chuàng)建 4GB 的虛擬地址空間,對(duì)于 windows 來(lái)說(shuō),默認(rèn)情況下每個(gè)用戶(hù)進(jìn)程可以占有 2GB 的私有地址空間;操作系統(tǒng)占有剩余的 2GB 空間。
在 32 位 x86 系統(tǒng)上 :
從
0x00000000
到
0x7fffffff
的空間中存放著 應(yīng)用程序代碼,全局變量,每個(gè)線(xiàn)程堆棧,
dll
代碼。
從
0x80000000
到
0xc0000000
的空間中存放著內(nèi)核和執(zhí)行體,
HAL(
硬件抽象層
),
引導(dǎo)驅(qū)動(dòng)程序。
從
0xc0000000
到
0xc0800000
的空間中存放著進(jìn)程頁(yè)表和超空間。
從
0xc0800000
到
0xffffffff
的空間中存放著系統(tǒng)高速緩存,分頁(yè)緩沖池,非分頁(yè)緩沖池。
? CreateProcess 打開(kāi)應(yīng)用程序文件 (.exe), 它先掃描該文件的文件頭,該文件頭里含有文件能運(yùn)行在那個(gè)環(huán)境之下,如果是 win32 環(huán)境,系統(tǒng)就直接加載文件的代碼和數(shù)據(jù)并輸入 (import) 該文件執(zhí)行所需的 dll 函數(shù)。如果不是 win32 環(huán)境比如是 os/2 的 .exe 則先加載相應(yīng)的環(huán)境子系統(tǒng),再由該環(huán)境加載該文件的代碼和數(shù)據(jù)以及該文件執(zhí)行所需的 dll 函數(shù)。
加載器負(fù)責(zé)把可執(zhí)行文件的數(shù)據(jù)段和代碼段映射到進(jìn)程的虛擬內(nèi)存空間中,讀入可執(zhí)行程序的導(dǎo)入符號(hào)表,然后根據(jù)這些符號(hào)表可以查找出該可執(zhí)行程序所有依賴(lài)的動(dòng)態(tài)鏈接庫(kù)。
? 進(jìn)程加載代碼和數(shù)據(jù)完畢后,就開(kāi)始創(chuàng)建線(xiàn)程來(lái)執(zhí)行進(jìn)程空間內(nèi)的代碼。進(jìn)程是靜態(tài)的,它只是線(xiàn)程的容器。一個(gè)進(jìn)程至少因該有一個(gè)線(xiàn)程 (main thread), 其它線(xiàn)程都是主線(xiàn)程通過(guò)調(diào)用 CreateThread 函數(shù)創(chuàng)建的。線(xiàn)程也是核心對(duì)象,他的實(shí)際創(chuàng)建者是 NtCreateThread 系統(tǒng)服務(wù)函數(shù)。一個(gè)線(xiàn)程只是一個(gè)線(xiàn)程核心對(duì)象和兩個(gè)堆棧 ( 一個(gè)核心堆棧,用于線(xiàn)程運(yùn)行在核心態(tài);一個(gè)用戶(hù)堆棧,用于線(xiàn)程運(yùn)行在用戶(hù)態(tài) ) ,線(xiàn)程與進(jìn)程類(lèi)似,也擁有線(xiàn)程核心對(duì)象計(jì)數(shù)和線(xiàn)程句柄。線(xiàn)程用于描述進(jìn)程中的運(yùn)行路徑。
?
每當(dāng)進(jìn)程被初始化時(shí),系統(tǒng)就要?jiǎng)?chuàng)建一個(gè)主線(xiàn)程。該線(xiàn)程與
c/c++
運(yùn)行時(shí)庫(kù)的啟動(dòng)代碼一道開(kāi)始運(yùn)行,啟動(dòng)代碼則調(diào)用進(jìn)入點(diǎn)函數(shù)
(
就是
main
函數(shù),它也是主線(xiàn)程的進(jìn)入點(diǎn)函數(shù)
)
,并且繼續(xù)運(yùn)行直到進(jìn)入點(diǎn)函數(shù)返回并且
c/c++
運(yùn)行時(shí)庫(kù)的啟動(dòng)代碼調(diào)用
ExitProcess
為止。每個(gè)線(xiàn)程都有自己的入口點(diǎn)函數(shù),主線(xiàn)程入口點(diǎn)函數(shù)名字必須是
main,wmain,WinMain
或
wWinMain.
而其他的線(xiàn)程入口點(diǎn)函數(shù)名字可使用任何名字。每個(gè)線(xiàn)程函數(shù)必須有一個(gè)返回值,它將作為線(xiàn)程的退出代碼。對(duì)于主線(xiàn)程來(lái)說(shuō),這個(gè)返回值將傳給
c/c++
運(yùn)行時(shí)庫(kù)的啟動(dòng)函數(shù)。
c/c++
運(yùn)行時(shí)庫(kù)的啟動(dòng)函數(shù)是一個(gè)程序調(diào)用的第一個(gè)函數(shù),它是在程序鏈接時(shí)由鏈接程序選擇相應(yīng)的啟動(dòng)函數(shù)并加到程序的開(kāi)始處。
c/c++
運(yùn)行時(shí)庫(kù)有四個(gè)版本的啟動(dòng)函數(shù),他們分別對(duì)應(yīng)不同類(lèi)型的應(yīng)用程序。比如,需要
ANSI
字符和字符串的
GUI
應(yīng)用程序的啟動(dòng)函數(shù)是
WinMainCRTStartup,
其對(duì)應(yīng)的進(jìn)入點(diǎn)函數(shù)是
WinMain,
需要
Unicode
字符和字符串的
GUI
應(yīng)用程序的啟動(dòng)函數(shù)是
wWinMainCRTStartup,
其對(duì)應(yīng)的進(jìn)入點(diǎn)函數(shù)是
wWinMain,
而需要
ANSI
字符和字符串的
CUI
應(yīng)用程序
(
如控制臺(tái)
console
程序
)
的應(yīng)用程序的啟動(dòng)函數(shù)是
mainCRTStartup,
對(duì)應(yīng)的入口點(diǎn)函數(shù)為
main;
需要
Unicode
字符和字符串的
CUI
應(yīng)用程序
(
如控制臺(tái)
console
程序
)
的應(yīng)用程序的啟動(dòng)函數(shù)為
wmainCRTStartup,
對(duì)應(yīng)的入口點(diǎn)函數(shù)為
wmain
。
c/c++
運(yùn)行時(shí)庫(kù)的啟動(dòng)函數(shù)
(
以
WinMainCRTStartup
為例
)
的功能如下
:
檢索指向新進(jìn)程的完整命令行指針;檢索指向新進(jìn)程的環(huán)境變量的指針;對(duì)
c/c++
運(yùn)行時(shí)的全局變量進(jìn)行初始化;對(duì)
c
運(yùn)行期的內(nèi)存單元分配函數(shù)
(
比如
malloc
,
calloc)
和其他低層
I/O
例程使用的內(nèi)存棧進(jìn)行初始化。為
C++
的全局和靜態(tài)類(lèi)調(diào)用構(gòu)造函數(shù)。
? 啟動(dòng)函數(shù)條用主函數(shù),進(jìn)入應(yīng)用程序的執(zhí)行。
? 當(dāng)主函數(shù)執(zhí)行完畢返回時(shí),啟動(dòng)函數(shù)就調(diào)用 c 運(yùn)行期的 exit() 函數(shù),將返回值 (nMainRetVal) 傳遞給啟動(dòng)函數(shù)。之后 exit() 便開(kāi)始收尾工作。
? 運(yùn)行時(shí)啟動(dòng)函數(shù)調(diào)用操作系統(tǒng)的 ExitProcess 函數(shù),將 nMainRetVal 傳遞給它,這使得操作系統(tǒng)能夠撤銷(xiāo)進(jìn)程并設(shè)置它的 exit 代碼。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
