C++运行时候库操作概述和整个程序运行流程
一、任何一個C/C++程序,它的背后都是一套龐大的代碼來進行支撐,以使得該程序能夠正常運行。這套代碼至少包括入口函數、及其依賴的函數所構成的函數集合。當然,它還應該包括各種標準函數(如字符串,數學運算等)的實。一般的程序運行過程如下:
1.操作系統創建進程后,把控制權交給程序的入口函數(gcc -e (_startEntryPoint)),這個函數往往是運行時庫的某個入口函數,glibc的入口函數是_start,msvc(vc6.0)是mainCRTStartup
2.入口函數對運行庫和程序運行環境進行初始化,包括堆、I/O、線程、全局變量構造函數(constructor)等。
3.調用MAIN函數,正式開始執行程序主體。
4.執行MAIN完畢,返回入口函數,進行清理工作,包括全局變量析構、堆銷毀、關閉I/O等,然后進行系統調用結束進程
二、啟動時庫主要功能模塊
1.啟動與退出,包括入口函數及其依賴函數
2.標準函數
3.I/O功能的封裝和實現,如提供PRINT
4.堆的封裝和實現
5.調試支持等
三、程序詳細運行過程
以下分析默認為windows靜態鏈接過程
1.程序執行前裝載器會把用戶的參數和環境變量壓入棧,接著操作系統把控制權交給mainCRTStartup入口函數。
用戶的參數:對應int main(int argc, char **argv)
環境變量:系統公用數據,系統搜索路徑等等
程序需要獲取用戶參數和環境變量均是從棧上獲取,需要理解棧幀的概念
2.初始化和OS版本相關的全局變量
3.初始化堆,每個進程都有屬于自己的堆。它是一次性從系統中申請一塊比較大的虛擬空間(實際需要時(如malloc)才會映射到物理頁),以后在進程中由庫的堆管理算法來維護這個堆。當堆不夠用時再繼續申請一塊大的虛擬空間繼續分配。可見,并非程序每次malloc都會調用系統API(API調用比較耗時,涉及到用戶態到內核態的上下文切換),效率比較高。
堆相關操作:
HeapCreate:創建一個堆,最終會調用virtualAlloc()系統API函數去創建堆。
HeapAlloc:malloc會調用該函數
HeapFree:free會調用該函數
HeapDestroy:摧毀一個堆
4.I/O初始化,繼承父進程打開文件表。可見,子進程是可以訪問父進程打開的文件。如果父進程沒有打開標準的輸入輸出,該進程會初始化標準輸入輸出。即初始化一下指針變量:stdin,stdout,stderr。他們都是FILE類型指針。在linux和windows中,打開文件對應于操作一個內核對象,其處于內核態,因此用戶態是不能直接操作該內核對象的。用戶只能操作與內核對象相關聯的FILE結構指針。對應關系是:
printf其實是調用stdout指針在屏幕上輸出 #define printf(args...) fprintf(stdout, ##args) Args...表示變長輸入參數。用以下四個宏根據棧來獲取。Va_list,Va_start,Va_arg,Va_end
5.獲取命令行參數和環境變量
6.初始化C庫的一些數據
7.全局變量構造,如各個全局類對象的構造函數調用和標記__attribute__((constructor))屬性的各個函數。它們都應該在進入main前進行調用。
需要調用運行時庫和C/C++編譯器、連接器的配合才能實現這個功能
1)編譯器編譯某個.cpp(設為main.cpp)文件時,會將所有的構造函數實現作為一個整體放到.init段,把析構函數實現放到.finit段,然后在,ctors段放置.init段的地址(該地址即是該文件的各個構造函數的總入口)。
2)運行時庫有一個庫是crtbegin.o,它的.ctors段放置的內容為-1,ctrend.o,她的.ctors段放置的內容也是-1。
3)用鏈接器進行連接:ld crtbegin.o main.o crtend.o 一定要按這種順序,否則出錯。鏈接后的.ELF文件是將以上各個文件的.init/.finit/.ctors等段分別合并。當然.data/.text段也會相應合并。
全局變量構造時即是遍歷.ctors段的內容,從-1(crtbegin.o)開始,再到-1(crtend.o)結束,中間每四個字節即是各個文件的構造入口函數指針,如果非0,即進行調用
8.注冊析構函數
為了支持C++類的析構函數,和標記__attribute__((destructor))屬性的各個函數在main之后會被調用,而且是按構造的相反順序進行調用的,同樣需要編譯器以及運行時庫的支持,原理跟構造相仿。只是為了逆序,使用了atexit注冊各個函數,注冊時在鏈表頭插入連接,main退出以后也是從鏈表頭開始獲取鏈表函數,并進行調用
9.執行函數主體
調用main函數執行,等待返回。在這里可以用到之前已經初始化的各種資源,如I/O,堆,申請釋放等等
10.調用析構函數
11.釋放堆
12.釋放其它資源
13.調用exit系統API退出進程
轉自:http://www.cnblogs.com/yueqian-scut/p/3952263.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的C++运行时候库操作概述和整个程序运行流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c内存管理详解
- 下一篇: C/C++程序从编译到最终生成可执行文件