程式編譯和鏈結原理理解

2021-08-17 13:52:32 字數 4201 閱讀 9841

一、本書解決的問題

本書主要介紹系統軟體的執行機制和原理,涉及在windows和linux兩個系統平台下,乙個應用程式在編譯、鏈結、和執行時所做的事,具體如下:

1.windows和linux作業系統下各自的可執行檔案、目標檔案格式?

2.普通的c/c++程式**如何編譯成目標檔案及程式的目標檔案如何儲存?

3.目標檔案如何被鏈結器鏈結到一起,並且形成可執行檔案?

5.可執行檔案如何被裝載,裝載到哪,並且執行?

6.可執行檔案與程序的虛擬位址空間之間如何對映?虛擬位址和實體地址之間的對映由系統完成,怎樣完成?

7.什麼是靜態鏈結,動態鏈結,兩者的區別,為啥要使用動態鏈結?

9.堆,棧,**段,資料段,bss段的理解?

10.執行庫,系統呼叫與api的理解?

二、相關書籍介紹

1.《linkers and loaders》 --介紹鏈結和裝在方面最為完整和權威的理論著作

2.《linux核心源**情景分析》 --基於linux2.4核心的,對於核心很多細節描述詳細

3.《深入理解計算機系統》 --對整個計算機硬體體系結構進行了深入淺出的介紹,是理解系統底層不可多得的書籍

4.《深入理解windows作業系統》 --深入理解windons核心最好的書籍

5.《advanced programming in the unix environment》--理解unix系統核心,執行庫和執行環境最好的選擇

1.計算機硬體的最為關鍵的三個部件:cpu,記憶體,i/o裝置

1)cpu及其架構的發展

1>cpu早期的核心頻率不高,跟記憶體的頻率一樣,故採用了用乙個匯流排(bus)將兩者聯絡起來。

2>由於很多的i/o裝置速度與cpu和記憶體慢很多,為了協調cpu和i/o裝置間的通訊,每個裝置都會有乙個相應的控制器,其相當於解決了不同速度之間的協議問題。

3>其實cpu的發展速度很快,導致記憶體的速度跟不上,故產生了與記憶體頻率一致的,cpu通過分頻和系統匯流排通訊;

4>北橋-滿足圖形裝置,cpu和記憶體之間的通訊,利用北橋晶元實現;

南橋-主要解決低速裝置和cpu之間的通訊

2)記憶體及其發展

位址空間不隔離

記憶體使用率較低

程式執行位址不確定

記憶體大小受限

2>採用的最基本的方法就是加入中間層,及引入虛擬位址概念

3>同時採用分段的方式,從應用程式的角度來分段儲存

4>為了提高記憶體的使用率,採用分頁的方式來實現

3)i/o裝置,採用分層的思想解決裝置多樣性的問題,其中會設計到很多裝置驅動架構,其主要是盡量多層次的挑出裝置的共同屬性,綜合使用。

2.執行緒

1)多執行緒問題

windows:核心有明確的程序和執行緒的概念並且有一系列的api來操作它;

linux:對多執行緒的支援比較貧乏,其並沒有真正意義上的執行緒概念,所有的實體都是任務,每乙個任務就可以理解成乙個單執行緒的程序,具有記憶體空間,執行屍體,檔案資源,當共享了同乙個記憶體空間的多個任務構成了乙個程序。

2)關於執行緒訪問許可權的理解

執行緒私有

執行緒之間共享(程序所有)

區域性變數

全域性變數

函式的引數

堆上的資料

tls資料

函式裡面的靜態變數

程式**,任何執行緒都有權利讀取並執行任何**

代開的檔案

3)使用者執行緒和核心執行緒

一般情況下,使用者執行緒都會有對應的核心執行緒,但並不是一一對應的,存在三種對應模型:一對一模型,一對多模型,多對多模型

3.系統軟體(用於管理計算機本身的軟體)

1)平台性的;如作業系統核心,驅動程式,執行庫,系統工具

四、靜態鏈結

1.編譯和鏈結

以下四個過程就是編譯器掩藏起來幫我們處理掉的過程

1)預編譯(生成*.i檔案)

1>將所有的「#define」刪除,並且展開所有巨集;

2>處理掉所有條件預編譯指令,如:「#if」、「#ifdef」、「#elif」、「#else」、「#endif」;

3>處理「#include」指令,這是乙個遞迴過程;

4>刪除所有的注釋「//」和「/* */」;

5>天劍行號和檔名標示

6>保留所有的#pragma編譯器指令,待編譯器使用;

2)編譯(生成*.o檔案,也叫目標檔案)

把預處理完的檔案進行一系列的詞法分析,語法分析,語義分析及優化後生成相對應的彙編**檔案

3)彙編

彙編器是將彙編**轉變成機器可以執行的指令,每乙個彙編語句幾乎都對應一條機器指令

4)鏈結(生成*.exe檔案,也叫可執行檔案)

1>位址和空間分配

2>符號決議

3>重定位

2.目標檔案

1)可執行檔案

1>windows下面pe格式

2>linux下面是elf格式,其格式分類見附錄:elf檔案型別

3>目標檔案、動態鏈結庫、靜態鏈結庫都是按照可執行檔案格式儲存的

2)目標檔案

1>目標檔案的組成:

b.程式指令

c.程式資料:資料段和.bss段

2>程式和資料分段的目的

a.可以標記為不同屬性,分開儲存:程式為唯讀,資料為可讀可寫

b.可以分開進行快取

c.指令可以重複使用,即指令共享

3>elf檔案詳細介紹

a.檔案頭:elf魔數,檔案機器位元組長度,資料儲存方式,版本,執行平台,硬體平台,入口位址,程式頭入口和長度,段表的位置和長度及數量等

b.段表:儲存這些段的基本資訊,段名,長度,在檔案中的偏移,讀寫許可權及段的其他屬性

c.重定位表:即為「.rel.text」段

d.字串表

3.靜態鏈結

靜態鏈結就是將幾個目標檔案鏈結起來形成乙個可執行檔案

1)空間和位址分配

1>按序合併:就是將各個目標檔案依次合併,這個問題是當目標檔案過多時,就會產生很多零散的段,位址對齊時會浪費空間

2>相似段合併:就是將相同段分配到一起,

2)符號解析和重定位

1>重定位通過分析重定位表來實現重定位

五、裝載和動態鏈結

1.可執行檔案的裝載

1)裝載方式

1>覆蓋裝入:直接按照執行檔案段大小進行對映即可

2>頁對映:

2)鏈結檢視和執行檢視

1>鏈結檢視

按可執行檔案進行分段,但考慮到執行檢視參考的屬性不同,故後面會對segment進行section轉化,其中還會涉及到段對齊等問題

2>執行檢視

a.可讀可執行段:

b.可讀可寫段:

c.可讀段:

3)窺探linux的程序記憶體對映

1>可執行檔案到vma的對映:

在建立程序時,即建立了可執行檔案的段到vma的對映,但沒有真正對映到實體地址

在linux程序記憶體訪問時,當沒有實體地址頁時就會產生頁錯誤,此時呼叫作業系統進行實體地址到vma的對映

2.動態鏈結

a.記憶體空間的限制,鏈結進所有需要的靜態檔案,會使執行檔案過大;

b.會存在鏈結進去很多重複檔案,浪費記憶體空間;

c.對於程式的部署,每次需要整個重新更新整個執行檔案。

2>動態鏈結;

a.增強了程式的可擴充套件性;

b.增強了程式的可執行性。

1>執行檢視中分開儲存**和資料,提高**的使用率;

2>位址重對映時會有問題,多個執行緒可能對應同意**段,不能進行位址重對映;

3>基於以上原因,產生了位址無關碼,每個執行緒都有自己對應的資料區,故可以那些需要重對映的位址和資料儲存在一起,這樣就產生了位址無關**

3.記憶體布局

1)程式的記憶體分配

1>對於linux而言,記憶體布局

kernel space

stack

dynamic libraries

heap

data

code

reserved

2)棧1>定義:乙個動態的記憶體區域,函式執行完了之後釋放,遵循規則:fifo

3>函式返回值:實現介面之間的通訊。

3)堆1>定義:棧會釋放,靜態區域只能在編譯時建立,結合兩者的優勢,產生了可以動態生成和釋放的堆

2>linux程序堆管理:

a.brk()系統呼叫

b.mmep()系統呼叫

3>堆演算法

a.鍊錶:鏈結鏈結所有的記憶體,然後按需查詢分配

b.點陣圖:記憶體大小全部固定,按需分配

c.記憶體池:結合兩者優勢

編譯安裝原理理解

configure從程式檔案角度出發是乙個可執行指令碼,執行此指令碼是為了生成makefile檔案,這個檔案是乙個相當於定的規矩的檔案,也就是顯式規則說明,在此可通過在configure後新增引數拉對安裝進行控制,比如說將配置檔案放在某個目錄下,將日誌檔案放在某個目錄下等,這個指令碼檔案的執行也是對...

從編譯原理理解遞迴

遞迴 相關概念 1 棧結構 2 終止條件 3 編譯原理 從最簡單的例子入手 demo1 public class fibonacci public static void main string args 輸出結果是3 2 1 demo2 public class fibonacci public ...

CSS 原理理解

網頁製作最初,html規定了 normal document stream 標準文件流 來規範元素在網頁中的顯示法則 標準文件流中元素分兩種 塊內元素,行內元素。行內元素的特點 span標籤 豎直margin中的塌陷現象,上下緊密排列的元素的外邊距並不是兩個元素外邊距之和,而是選取那個最大的外邊距作...