1. 程式人生 > >讀書筆記第三周《程序員的自我修養》

讀書筆記第三周《程序員的自我修養》

都是 解決 .dll 空間 運行 .lib 不同 多目標 模型

第三周讀書筆記 《程序員的自我修養》

??計劃對這本書是精讀,這周讀了3,4章。

第三章 目標文件裏有什麽


?? 首先介紹了目標文件的格式,Windows下是pe-coff,linux下是elf,他們都源於coff,這與操作系統的發展歷史有關,而且不僅可執行文件按這種格式存儲,動態鏈接庫(.dll),靜態鏈接庫(.lib)都是如此存儲。
?? 在目標文件中,信息以段的形式存儲(微機原理講過),總體被分為指令與數據兩部分。代碼編譯後的機器指令放在代碼段(.text),全局變量與局部靜態變量放在數據段(.data),未初始化的全局變量或者局部靜態變量放在.bss段,此段為這些變量預留位置(初始化後才占用內存).
??看到這裏必然會疑惑為什麽要分開呢?
??一是是數據必然要有讀寫的權限,假如對於指令給予寫權限可能會帶來隱患
??二是可以適應CPU的cache體系,現代cache就分成了指令緩存與數據緩存。
??三是最重要的,系統運行多個相同程序的時候,他們可以共享指令,還有文本圖片等,當然數據區是獨立的,這極大的節省了內存。
?? 之後還介紹了文件頭,以及對於一段代碼編譯後存放的分析。引起我興趣的是關於重定位的文件,.o文件裏會有一個叫做。rel.text的文件,類型為SHT——REL,存放代碼段,數據段中重定位表的位置,並以符號文件作為接口
?? 當各種庫文件出現,不可避免就要解決用戶自己定義的變量與庫文件變量可能重名的問題,c是在所有用戶自定義編譯後前面加_(但是多個用戶寫出的代碼還是可能會沖突),之後像c++便有了命名空間之類的概念。
?? c++的復雜特性(類,繼承,重載,命名空間)為符號管理增加了難度,人們發明了符號修飾機制解決了重載問題。對於返回變量,形參不同的函數,利用其特征生成不同的簽名以區別。註意不同的編譯器會采取不同的簽名方法,這也導致不同的編譯器不能互操作。

第四章 靜態鏈接


?? 講述了兩個文件鏈接後在輸出文件中的內存位置,為了避免浪費儲存空間(各個段是用頁的形式儲存的),大都采用相似段合並的方法。一般分為兩步,1地址與空間分配,2符號解析與重定位。
?? C++因為其語言特性使其必須編譯器與鏈接器共同支持才能完成工作。 第一個問題是重復代碼消除,例如不同的文件中實例化了相同的模板,每個文件各自以不同參數單獨占據一個段,合並時將相同的實例合並在一個段。
??再就是解決目標文件中沒有調用的函數的處理,因為現在的庫都十分龐大,當鏈接時,很容易沒用的函數包括進來,編譯器一般會給與選項,可以讓所有函數分到不同的段中,這樣鏈接的時候就可以舍棄無用的函數段,但是因為要計算函數依賴關系,會較低編譯速度。
??c++中ABI(二進制層面的接口)兼容性變差,導致不同公司用相同編譯器編譯的二進制代碼都無法兼容,除非將所有源代碼一塊編譯,對大型項目十分不友好。
?? 靜態庫就可以看成一些目標文件的集合,就是許多目標文件打包,windows上最常見的就是IDE自帶的運行庫。理論上我們可以從庫中提取我們想要的目標文件,與我們寫的代碼生成的目標文件來鏈接來生成最終的目標文件。值得註意的是庫文件中一個目標文件一般只包含一個函數,這樣是為了避免鏈接時候將無用函數鏈接進來形成空間的浪費。
?? 後面一些鏈接控制什麽的實在是太低層了,不想看了。
?? 為了解決不同硬件平臺導致的目標文件格式的不同,這對像是GCC一樣的跨平臺工具提出了要求,BFD庫就是解決了這一問題。其可以看作這些不同目標文件的一個接口,其把目標文件抽象成一個抽象的模型,這樣就使得目標文件與編譯器與鏈接器分割開來。
?? 以上就是本周看的內容。

讀書筆記第三周《程序員的自我修養》