一、本書解決的問題
本書主要介紹系統軟體的執行機制和原理,涉及在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中的塌陷現象,上下緊密排列的元素的外邊距並不是兩個元素外邊距之和,而是選取那個最大的外邊距作...