《程序員的自我修養(yǎng)——鏈接欣尼、裝載與庫》讀書筆記(一)

在被各種編譯問題折磨了一個假期后爆雹,突然想起了曾經(jīng)借過的程序員神書——《程序員的自我修養(yǎng)——鏈接停蕉、裝載與庫》愕鼓。初見這本書還是個沒見過Linux萌新,看的云里霧里慧起。今天正好跟著新開的編譯原理課菇晃,好好捋順一下這一大堆曾經(jīng)視若不見的底層。


0x0 導(dǎo)讀

有故事的書要先讀序言蚓挤,有技術(shù)的書要先看目錄磺送。作者很貼心的給出了導(dǎo)讀,也算是給這本書劃了一道門檻灿意。

0x01 應(yīng)具備的知識

  • 了解C/C++編程
  • 有一定x86匯編基礎(chǔ)
  • 了解操作系統(tǒng)估灿、編程技巧和計算機系統(tǒng)結(jié)構(gòu)基本概念
  • 最好有Linux的編譯體驗(斗膽新添)

0x02 大致涉及內(nèi)容

  • 靜態(tài)鏈接過程
  • 裝載與動態(tài)鏈接
  • 庫與運行庫

0x03 想要達(dá)到的目的

  • 了解Win、Linux下各自的可執(zhí)行文件缤剧、目標(biāo)文件格式
  • C/C++程序編譯詳情
  • 目標(biāo)文件鏈接過程詳情
  • 可執(zhí)行文件裝載與執(zhí)行
  • 可執(zhí)行文件與進程虛擬空間映射
  • 動態(tài)鏈接
  • 堆棧
  • 函數(shù)調(diào)用
  • 運行庫(Glibc和MSVC CRT實現(xiàn)分析)
  • 實現(xiàn)一個 Mini CRT

應(yīng)當(dāng)掠過的內(nèi)容

本書第一章給出的是一些基礎(chǔ)內(nèi)容的回顧馅袁,也是作者出于“降低閱讀門檻”目的下的給出的知識補丁。由于不是筆記的重點內(nèi)容荒辕,這里簡單列舉一下涉及的內(nèi)容汗销,有興趣的朋友可以選擇了解:

  • 計算機硬件發(fā)展簡述(SMP與多核)
  • 計算機軟件體系結(jié)構(gòu)(API、系統(tǒng)調(diào)用接口)
  • 操作系統(tǒng)發(fā)展(CPU分配策略發(fā)展抵窒、設(shè)備驅(qū)動意義)
  • 虛擬內(nèi)存(隔離弛针、分段、分頁)
  • 線程(意義李皇、分配策略與調(diào)度削茁、搶占、安全、優(yōu)化)

1 靜態(tài)鏈接

1.1 高級語言程序處理過程

高級語言程序處理過程
  • 預(yù)編譯:展開所有的宏定義茧跋、處理所有的預(yù)編譯指令朦拖、遞歸包含頭文件并將其中邏輯插入需要的地方、刪除所有注釋厌衔、添加行號和文件名標(biāo)識璧帝、保留所有#pragma指令

  • 編譯:將高級語言的源程序變換成低級語言的目標(biāo)程序的過程,可以使編程者不必過多考慮與機器有關(guān)的細(xì)節(jié)富寿。

  • 匯編:將匯編代碼轉(zhuǎn)換成機器可以執(zhí)行的命令睬隶。

  • 鏈接:把一大堆用到的文件拼接到一起,通過符號表解析和重定位等最終輸出可加載页徐、可執(zhí)行的目標(biāo)文件苏潜。

1.2 編譯過程

編譯過程

☆中間每個步驟都與表格管理出錯處理相關(guān)聯(lián)☆

  • 詞法分析:在掃描器內(nèi)利用有限狀態(tài)機的算法將源代碼中的字符序列分割成一系列的符號(Token)变勇。
    一般分為:關(guān)鍵字恤左、標(biāo)識符、常量搀绣、特殊符號

  • 語法分析:由語法分析器利用上下文無關(guān)算法飞袋,將這些符號生成語法樹
    語法樹以表達(dá)式為節(jié)點链患,表達(dá)式只能為常量巧鸭、標(biāo)識符、(A)麻捻、A※B 之一纲仍,其中A、B為表達(dá)式贸毕,※為一個運算符

eg:id1:=id2+id3*10 生成語法樹:

id1:=id2+id3*10 生成語法樹
簡化后的語法樹
  • 語義分析:對表達(dá)式語法層面的分析郑叠,同時為代碼生成階段收集類型信息。
    該階段并未動態(tài)裝配明棍,所以只是靜態(tài)分析

  • 中間代碼生成:一般是三地址編碼或者四元算式乡革,轉(zhuǎn)換成內(nèi)部的表達(dá)方式。
    ( IntToReal ,10 , -, t1)击蹲,
    ( *, id3, t1, t2 )署拟,
    ( +, id2, t2, t3 )歌豺,
    ( :=, t3 , - , id1 )

  • 代碼優(yōu)化:對中間代碼進行優(yōu)化。
    ( *, id3, 10.0, t1 )类咧,
    ( +, id2, t1, id1 )

1.3 鏈接過程

程序并不是一成不變的蟹腾,修改后的地址變化問題非常繁瑣。為了簡化編程区宇,人們開始使用符號來代指位置娃殖,其地址在使用過程中動態(tài)插入到需要的位置议谷。重新計算各個目標(biāo)位置的過程即為重定位

運行一個程序所需要的代碼量可能非常龐大卧晓,而且很大一部分代碼可重用性很高芬首,而且模塊之間耦合度很低。于是人們便將代碼分割成了很多部分逼裆,使用時再將各個部分拼接起來,這個過程就是鏈接胜宇,這些部分在不同的語言中有不同的形式,比如引用桐愉、包、或者庫狈究。

可想而知盏求,鏈接過程中必定存在很多內(nèi)部或外部的函數(shù)或變量,所以這個過程包括了很多諸如地址空間分配碎罚、符號決議纳像、重定位等步驟。

1.4 目標(biāo)文件

可執(zhí)行文件:主要是Windows下的PE(Portable Executable)和Linux下的ELF(Executable Linkable Format)憔购,他們都是COFF(Common file format)格式的變種岔帽。

目標(biāo)文件:源碼編譯后還未經(jīng)過鏈接的中間文件玫鸟,內(nèi)容與結(jié)構(gòu)與可執(zhí)行文件相似屎飘,所以一般采取同種格式存儲。

  • 可重定位文件:代碼+數(shù)據(jù)钦购,可用來鏈接成可執(zhí)行文件或共享目標(biāo)文件。
    如 Linux .o 和 Windows .obj

  • 可執(zhí)行文件:可以直接執(zhí)行葵萎。
    如 Linux .sh 和 Windows .exe

  • 共享目標(biāo)文件:代碼+數(shù)據(jù)唱凯,鏈接器使用它們可重定位或共享目標(biāo)文件鏈接生成新的目標(biāo)文件,或者與可執(zhí)行文件結(jié)合波丰,作為映像一部分運行。
    如 Linux .so 和 Windows .dll

  • 核心轉(zhuǎn)儲文件:程序意外終止時轉(zhuǎn)儲一些信息爽蝴。
    如 Linux core dump

目標(biāo)文件格式:目標(biāo)文件根據(jù)信息的不同屬性將其按“段”存儲纫骑。

段存儲舉例

需要特別說明的幾點:

  • 文件頭:存儲了很多文件信息,后面會專門分析先馆。
  • 代碼與數(shù)據(jù)分離:便于讀寫權(quán)限分配、數(shù)據(jù)獨立邏輯共享梅惯、提高命中率仿野。
  • 預(yù)留段:未賦值或值為0的標(biāo)識符將暫時不被分配內(nèi)存,只在此處聲明預(yù)留空間脚作。
  • 必要部分:文件頭、代碼段劣针、數(shù)據(jù)段亿扁、預(yù)留段。
  • 非必要部分:還有很多魏烫。

Ps: 有關(guān)ELF內(nèi)部數(shù)據(jù)的詳細(xì)格式這里有篇不錯的博客 => 傳送門

1.5 符號問題

無論是源代碼還是依賴文件肝箱,大量的函數(shù)和變量鏈接到一起后在全局范圍內(nèi)很容易造成沖突稀蟋。早期C語言與Fortran語言通過在前后添加“_”來進行區(qū)別,但在越來越多語言的后來并未很好的解決問題骏融。

1.5.1 C++的符號修飾

C++本身的繼承和重載就對函數(shù)區(qū)分有很高要求萌狂,于是C++引入了函數(shù)簽名的機制。所有符號都以“_Z”開始茫藏,對于嵌套的名字,后面緊跟“N”并以“名字字符串長度+E”結(jié)尾务傲,中間添加名稱空間和類的名字。最后再添加參數(shù)類型的簡寫完成名稱改造看杭。

eg: N::C::func(int) ==> _ZN1N1C4funcEi

1.5.2 強與弱

強符號與弱符號:全局范圍內(nèi)重復(fù)定義符號時挟伙,若是強符號則報錯。選擇時優(yōu)先選擇強符號尖阔,若全是弱符號則選擇長度最大的一個贮缅。
可以使用__attribute__((weak)) symbool = 2; 定義弱符號

強引用與弱引用:引用在被鏈接成可執(zhí)行文件是需要被正確決議携悯,若強引用丟失則報錯筷笨,弱引用丟失則忽略龟劲。


小結(jié)

盡管書剛讀了五分之一,只看完了一點點定義與格式昌跌,但也是很多次心里過癮的大呼“原來如此”。與第一次讀書時的感覺截然不同答恶,在實際問題中的掙扎讓現(xiàn)在的閱讀變得更有目的性和體驗感,期待接下來繼續(xù)讀下去的豐富收獲悬嗓。

PS:有興趣的同學(xué)可以去查查書里講到一個很好玩的故事。搜索的關(guān)鍵詞:馬屁股 航天飛機燕酷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末周瞎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酱讶,更是在濱河造成了極大的恐慌彼乌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件软免,死亡現(xiàn)場離奇詭異焚挠,居然都是意外死亡,警方通過查閱死者的電腦和手機蝌衔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門噩斟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剃允,你說我怎么就攤上這事〗烽梗” “怎么了牡肉?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毛俏。 經(jīng)常有香客問我,道長煌寇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任擦盾,我火速辦了婚禮淌哟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腐碱。我一直安慰自己掉弛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布谋作。 她就那樣靜靜地躺著乎芳,像睡著了一般遵蚜。 火紅的嫁衣襯著肌膚如雪奈惑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天寂殉,我揣著相機與錄音原在,去河邊找鬼。 笑死焕檬,一個胖子當(dāng)著我的面吹牛澳泵,可吹牛的內(nèi)容都是我干的兼呵。 我是一名探鬼主播腊敲,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼维苔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了没宾?” 一聲冷哼從身側(cè)響起沸柔,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎褐澎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迁酸,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡俭正,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年掸读,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺枉。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姥闪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出筐喳,到底是詐尸還是另有隱情,我是刑警寧澤避归,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布梳毙,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏坷襟。R本人自食惡果不足惜生年,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望档叔。 院中可真熱鬧,春花似錦衙四、人聲如沸侵贵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漱抓。三九已至,卻和暖如春乞娄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仪或。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工范删, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人到旦。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓添忘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搁骑。 傳聞我的和親對象是個殘疾皇子又固,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容