阿龙的学习笔记---《程序员自我修养-链接、装载与库》读书笔记(一)
生活随笔
收集整理的這篇文章主要介紹了
阿龙的学习笔记---《程序员自我修养-链接、装载与库》读书笔记(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
記錄筆記,因為看了好久還沒看完…真的是,但是雖然后面的沒看完,但我前面的頁快忘完了呀,記錄一下吧還是。
一、 溫故而知新
- 從計算機組成原理之類的開始講,說明這部分還是蠻重要的,雖然也快忘完了。
- 講到操作系統,這個的確也與程序運行息息相關。
- 講到了一個線程安全與編譯器的問題,雖然放在這怪怪的,但是很有趣:
-
雖然如我們一般所知,加鎖是可以在簡單情況下保證線程安全的,但是假如編譯器為了提高運行速度而優化,假如將一個變量先放在了寄存器中,然后暫時不寫回,過了一段時間才寫回內存,那么這個就會有問題了,即使正確加鎖也線程不安全了。
-
上面這個問題,C/C++的volatile可以解決,他做兩件事:
- 阻止編譯器為了提高速度將一個變量緩存到寄存器內而不寫回。
- 阻止編譯器調整操作 volatile變量的指令順序。
-
-
再有一種情況是:編譯器會優化語句執行的順序,那么就沒有太優雅的方式,通常情況下是調用CPU提供的一條指令,這條指令常常被稱為 barrier,barrier指今會阻止CPU將該指令之前的指令交換到barrier之后,反之亦然。
二、 編譯和鏈接
-
從代碼到執行
- 從hello.c到a.out,有這么幾個步驟:分別是預處理( Prepressing),編譯(Compilation)匯編(Assembly)和鏈接( Linking)。
- 預編譯:主要處理代碼中以“#”開頭的預編譯指令。大概就是展開#include,展開#define宏定義,處理#if,#ifdef等條件預編譯,刪除所有注釋,添加行號和文件名標識。.c文件會被預編譯成.i文件。
- 編譯:是把預處理的文件進行一系列的 詞法分析、語法分析、語義分析、優化操作,生成匯編代碼。是程序構建的核心部分。.i 文件會被便以為 .s 文件。
- 匯編: 匯編器將匯編代碼轉變為機器可以認識的代碼,機器代碼,只用按照匯編指令和機器指令的對照表一一翻譯即可。輸出目標文件 ,即.o 文件。
- 鏈接:輸出的目標文件運行時,仍然需要其他代碼的支持。比如你添加一個頭文件,為啥就能調用頭文件里的函數了呢?因為有鏈接器,讓你的程序能夠找到那些函數、變量等。同樣對于調用printf函數也需要鏈接。
-
編譯部分做了什么?
- 詞法分析:源代碼輸入進來之后,要分詞,比如要把a=2; 分解為a, =, 2三部分,類型是標識符、值符號、數字。
- 語法分析:對上面的記號進行分析,C語言的一個語句是一個表達式,復雜的語句則是多個表達式的結合,則需要把表達式分開,分解成語法樹的方式是利于計算機分析的。
- 比如:
- 根據符號的優先級等規則,會被分解為:
- 語義分析:上面只是分析出了語句是什么樣的,并不知道是否合理,有意義。語義分析通常包括聲明和類型的匹配,類型轉換。
- 目標代碼生成:編譯器把優化得來的中間代碼轉換為虎目標機器代碼,根據不同的機器,會有不同的類型程度等。
-
鏈接部分做什么?
- 此處先看靜態鏈接。程序模塊化之后,不同模塊之間獨立編譯,鏈接這個步驟就是將各模塊之間組合起來。
- 鏈接主要包括了:地址和空間分配、符號決議、重定位這些步驟。
- 比如我們使用到foo.c中的一個函數foo(),我們main.c中調用時,必須要知道這個foo()函數的地址,編譯期間是不知道的,那么需要先擱置(置為0),等最后鏈接的時候再去修正這些地址。
- 修正地址的過程叫做重定位,每個地方叫重定位入口。
三、目標文件
-
目標文件是編譯完成后的文件,從結構上說已經是可執行文件的格式了,只是還沒調整一些符號的地址等。
-
Linux下可執行文件的格式是ELF文件。
-
目標文件里面有編譯過后的代碼指令、數據,還有一些鏈接時用的信息比如符號表、調試信息等。
-
目標文件一般以段(Segment)的形式存儲,比如編譯后的機器指令被放在代碼段.text,全局變量局部靜態變量數據經常被放在數據段.data。
-
linux下的目標文件是ELF文件,大致看一下ELF的結構:
- 文件頭:ELF的文件頭中定義了ELF魔數、文件機器字節長度數據存儲方式、版本、運行平臺、AB版本、ELF重定位類型、硬件平臺、硬件平臺版本、入口地址、程序頭入口和長度、段表的位置和長度及段的數量等。這些數值中有關描述ELF目標平臺的部分,與我們常見的32位 Intel的硬件平臺基本上一樣。
- 段表:我們知道ELF文件中有很多各種各樣的段,這個段表(Section Header Table)就是保存這些段的基本屬性的結構。段表是ELF文件中除了文件頭以外最重要的結構,它描述了ELF的各個段的信息,比如每個段的段名、段的長度、在文件中的偏移、讀寫權限及段的其他屬性。
- 重定位表:鏈接器在處理目標文件時,須要對且標文件中某些部位進行重定位,即代碼段和數據段中那些對絕對地址的引用的位置。這些重定位的信息都記錄在ELF文件的重定位表里面,對于每個須要重定位的代碼段或數據段,都會有一個相應的重定位表。、
-
鏈接的接口——符號
- 鏈接需要處理的就是符號,也就是函數和變量,統稱為符號。每一個目標文件會有相應的符號表,值就是符號的地址。
-定義在本文件的全局符號,可以被其他文件引用;而本文件中引用的全局符號,但沒在本文件定義,叫做外部符號。 - 符號表.symtab會有符號的具體信息。
- C++由于引進了復雜特性,符號增加了符號修飾,來解決函數重載、繼承、虛擬機制等問題導致的符號重名。
- 鏈接需要處理的就是符號,也就是函數和變量,統稱為符號。每一個目標文件會有相應的符號表,值就是符號的地址。
-
目標文件中還有可能保存一些調試信息,調試時必須提前知道源代碼和目標代碼之間的關系,來設置斷點、監控變量。(例如Qt中可以選擇Debug版本)但是比較占空間。
總結
以上是生活随笔為你收集整理的阿龙的学习笔记---《程序员自我修养-链接、装载与库》读书笔记(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【手机投影】安卓手机投影到WIN10
- 下一篇: ffmpeg截取视频片段(傻瓜教程)