现成
01靜態(tài)鏈接 :01將可重定位的文件和命令行變成完全鏈接的、可加載、可運(yùn)行的目標(biāo)文件;02可重定位目標(biāo)文件由各代碼和數(shù)據(jù)節(jié)組成;
完成靜態(tài)鏈接,鏈接器要完成以下兩個(gè)工作:
1)符號(hào)解析,將每一個(gè)符號(hào)引用正好和一個(gè)符號(hào)定義關(guān)聯(lián)起來(lái);
2)重定位:可重定位的目標(biāo)文件地址都是從零開(kāi)始的,連接器通過(guò)吧每個(gè)符號(hào)定義與一個(gè)內(nèi)存位置關(guān)聯(lián)起來(lái),從而重定位這些節(jié),然后修改所有對(duì)這些符號(hào)的引用,使得他們指向這個(gè)內(nèi)存位置。
02目標(biāo)文件:分類 可重定位目標(biāo)文件;可執(zhí)行目標(biāo)文件;共享目標(biāo)文件;
03符號(hào)和符號(hào)表:
定義:符號(hào)表記錄了目標(biāo)模塊定義的符號(hào)和引用的符號(hào)信息。三種符號(hào)類型:
1.由模塊m定義并能被其他模塊引用的全局符號(hào),非靜態(tài)的C函數(shù)和全局變量;
2.由其他模塊定義并被模塊m引用的全局變量;
3.由目標(biāo)模塊定義和引用的局部符號(hào),表現(xiàn)為靜態(tài)全局變量和函數(shù);
符號(hào)解析:鏈接符號(hào)引用與符號(hào)定義
a.全局符號(hào)的多重定義問(wèn)題
強(qiáng)符號(hào):已被初始化的全局變量和函數(shù)
弱符號(hào):未被初始化的全局變量
b.規(guī)則
1:不允許有多個(gè)同名的強(qiáng)符號(hào)
2:如果有一個(gè)強(qiáng)符號(hào)和多個(gè)弱符號(hào)同名,選強(qiáng)符號(hào)
3:如果有多個(gè)弱符號(hào)同名,從其中任選一個(gè)
c.符號(hào)的地址由鏈接器確定,但符號(hào)的大小以及其類型在編譯器就已經(jīng)確定了,,鏈接器只負(fù)責(zé)解析和重定位符號(hào)確認(rèn)符號(hào)的地址,同名符號(hào)有且僅有一個(gè)地址
d.靜態(tài)鏈接可選方式:
1)一組可重定位目標(biāo)文件
2)所有相關(guān)的目標(biāo)模塊打包成一個(gè)單獨(dú)文件---靜態(tài)庫(kù)(存檔文件)
e.使用靜態(tài)庫(kù)來(lái)解析符號(hào)
1)一個(gè)特殊現(xiàn)象:
一個(gè)靜態(tài)庫(kù)被解析后需后面的靜態(tài)庫(kù)使用若,,,
2)過(guò)程:符號(hào)解析時(shí),鏈接器從左到右按照他們?cè)诰幾g器驅(qū)動(dòng)程序命令行上出現(xiàn)的順序來(lái)燒描可重定位目標(biāo)文件和存檔文件(如.c--.o)。鏈接器維護(hù)三個(gè)集合:所有目標(biāo)模塊集合E;未定義的集合U;定義的集合D;
燒描開(kāi)始,鏈接器來(lái)判斷輸入f是什么,若是目標(biāo)文件,f添加到E,修改U/D來(lái)反應(yīng)f中的符號(hào)定義和引用;若f是存檔文件,鏈接器就嘗試匹配U中未解析的符號(hào)和由存檔文件成員定義的符號(hào),若存檔文件成員m中有已定義的符號(hào),m放E,修改U/D;如果鏈接器完成掃描后,U非空,則鏈接器輸出錯(cuò)誤并終止,否則,它會(huì)合并和重定位E中的目標(biāo)文件;
04重定位和加載?
01) 重定位 (可結(jié)合靜態(tài)鏈接的兩個(gè)步驟作答)
需要的術(shù)語(yǔ):
a.重定位節(jié)和符號(hào)定義:聚合所有目標(biāo)文件的相同節(jié),鏈接器開(kāi)始將運(yùn)行時(shí)內(nèi)存地址賦給每一個(gè)節(jié)和每一個(gè)符號(hào) ☆☆☆
b.重定位節(jié)中的符號(hào)引用,鏈接器修改代碼節(jié)和數(shù)據(jù)節(jié)中的每個(gè)符號(hào)引用,使得他們執(zhí)行正確的運(yùn)行時(shí)地址。
02)過(guò)程:
a.一個(gè)概念,當(dāng)匯編器遇到未知的符號(hào)引用,就會(huì)生成一個(gè)重定位條目,代碼的重定位條目存放在 . rel.text中,已初始化數(shù)據(jù)的重定位條目放在.rel.data中
重定位結(jié)構(gòu)的結(jié)構(gòu):
typedef struct{long offset; //符號(hào)相對(duì)節(jié)的偏移long type:32;symbol:32;long addend; }Elf64_Rela;b.符號(hào)引用的重定位
只講兩種基本的重定位類型:
01相對(duì)引用
02絕對(duì)引用
03)加載 ☆☆☆
1)背景:elf可執(zhí)行文件的格式跟可重定位的格式是很相似的
2)可執(zhí)行目標(biāo)文件的加載
?加載器將目標(biāo)文件的代碼和數(shù)據(jù)復(fù)制到內(nèi)存中,然后跳轉(zhuǎn)到入口點(diǎn)來(lái)運(yùn)行即_start函數(shù)的地址;
?05 動(dòng)態(tài)鏈接庫(kù)
?1)出現(xiàn)的原因:為了解決靜態(tài)庫(kù)維護(hù)還是相對(duì)麻煩以及很多共用的庫(kù)在內(nèi)存中有很多碎片造成的內(nèi)存浪費(fèi)。
2)動(dòng)態(tài)鏈接:共享庫(kù)在加載或運(yùn)行時(shí)加載到任意內(nèi)存位置,并和在內(nèi)存中的程序鏈接起來(lái),由 動(dòng)態(tài)鏈接器完成。
3)相關(guān)細(xì)節(jié):
動(dòng)態(tài)鏈接不會(huì)復(fù)制共享庫(kù)的代碼和數(shù)據(jù)段,僅會(huì)復(fù)制一些重定位信息和符號(hào)表;
信息和符號(hào)表
共享庫(kù)中會(huì)有一個(gè) .interp節(jié),這個(gè)節(jié)包含動(dòng)態(tài)鏈接器的路徑名,動(dòng)態(tài)鏈接器本身就是一個(gè)共享目標(biāo)如(ld-linux.so)。
當(dāng)運(yùn)行一個(gè)可執(zhí)行文件時(shí),加載器會(huì)通過(guò).interp節(jié)的信息找到動(dòng)態(tài)鏈接器來(lái)運(yùn)行,而動(dòng)態(tài)鏈接器重定位相關(guān)的.so來(lái)完成鏈接任務(wù):
? 位置無(wú)關(guān)代碼PIC(position independent code):共享庫(kù)若想要被進(jìn)程共享就要求使用位置無(wú)關(guān)代碼,位置無(wú)關(guān)代碼是可以加載到內(nèi)存的任何位置,而無(wú)需鏈接器修改即可以加載和重定位;
06 異常和進(jìn)程
異常就是控制流突變,用來(lái)響應(yīng)處理器狀態(tài)中的某個(gè)變化,一部分由硬件實(shí)現(xiàn),一部分
由操作系統(tǒng)來(lái)實(shí)現(xiàn),每個(gè)異常都會(huì)被分配一個(gè)異常號(hào),一些由硬件設(shè)計(jì)者來(lái)分配,常
見(jiàn)的有:內(nèi)存缺頁(yè),算術(shù)溢出,內(nèi)存訪問(wèn)違規(guī),除零,一些由內(nèi)核設(shè)計(jì)者分配,常用的
有系統(tǒng)調(diào)用和外部I/o設(shè)備的信號(hào),異常有如下分類:中斷,故障,陷阱,終止。
其中中斷是異步發(fā)生的,中斷函數(shù)處理結(jié)束后返回下條指令,陷阱是同步的總是返回
下條指令,故障時(shí)同步的,由潛在可恢復(fù)的錯(cuò)誤造成(缺頁(yè)),返回當(dāng)前的指令,終止
同步的,不可恢復(fù),不會(huì)返回。
28/539
a.異常處理寫過(guò)程調(diào)用的一些不同之處
01返回地址不一樣,異常返回fizz需要根據(jù)異常類型來(lái)確定
02異常處理時(shí),處理器將一些額外的處理狀態(tài)壓入棧中
03若是由用戶態(tài)進(jìn)入內(nèi)核態(tài),則異常處理便用內(nèi)核棧
04異常處理程序運(yùn)行在內(nèi)核態(tài)
b.四種不同類型
中斷:不是由一條專門的指令造成的,它是處理器在每次執(zhí)行一條指令后檢測(cè)是否有中斷產(chǎn)生:
陷阱和系統(tǒng)調(diào)用:陷阱是有意義的異常,像中斷處理程序一樣,陷阱處理程序?qū)⒎祷叵乱粭l指令。陷阱最重要的作用是
在用戶程序和內(nèi)核之間提供一個(gè)像過(guò)程一樣的接口,叫做系統(tǒng)調(diào)用。系統(tǒng)調(diào)用都有一個(gè)服務(wù)號(hào),指令“syscall n”來(lái)請(qǐng)求服務(wù)n;
,
中斷與系統(tǒng)調(diào)用的區(qū)別:系統(tǒng)調(diào)用采用陷阱門,中斷進(jìn)入中斷服務(wù)cpu自動(dòng)關(guān)閉中斷IF清0,防止嵌套;陷阱門進(jìn)入服務(wù)程序時(shí)
IF不變,是開(kāi)中斷下進(jìn)行的,所有系統(tǒng)調(diào)用可被中斷;
?系統(tǒng)調(diào)用與一般程序區(qū)別:調(diào)用的棧不同,一個(gè)運(yùn)行在內(nèi)核模式一個(gè)運(yùn)行在用戶模式;
故障:若故障能夠被恢復(fù),則返回到引起故障的指令,否則終止;
終止:不可恢復(fù)的錯(cuò)誤。
?
進(jìn)程:
a.定義:一個(gè)執(zhí)行中的程序的實(shí)例。
進(jìn)程與程序的區(qū)別:程序是一堆代碼可以作為目標(biāo)文件存在于磁盤上,或者作為段存在于地址空間中,進(jìn)程是執(zhí)行程序的一個(gè)具體實(shí)例,程序總是運(yùn)行在某個(gè)進(jìn)程的上下文中。
b.進(jìn)程提供應(yīng)用程序的關(guān)鍵抽象:
一個(gè)獨(dú)立的邏輯控制流,它提供一個(gè)假象,好像我們的程序獨(dú)占地使用處理器。
一個(gè)私有的地址空間,它提供一個(gè)假象,好像我們的程序獨(dú)占地使用內(nèi)存系統(tǒng)。
c.邏輯控制流
PC值的序列-邏輯流
?d.用戶模式下訪問(wèn)內(nèi)核
唯一的模式就是通過(guò)異常(中斷、故障、陷阱)
處理器通常是用某個(gè)控制寄存器中的一個(gè)模式位,該寄存器描述了當(dāng)前進(jìn)程享有的特權(quán)。當(dāng)設(shè)置了模式位時(shí),進(jìn)程就運(yùn)行
在內(nèi)核模式中(也叫超級(jí)用戶模式)一個(gè)運(yùn)行在內(nèi)核模式的進(jìn)程可以執(zhí)行指令集中的任何指令,并可以訪問(wèn)系統(tǒng)中的
任何內(nèi)存位置。沒(méi)有設(shè)置,就是普通用戶模式,不允許執(zhí)行特權(quán)指令,比如停止處理器等;
e.上下文切換過(guò)程
每個(gè)進(jìn)程維持一個(gè)上下文,上下文是內(nèi)核重新啟動(dòng)一個(gè)被搶占的進(jìn)程所需的狀態(tài)。
過(guò)程:1保存當(dāng)前進(jìn)程的上下文,2恢復(fù)某個(gè)先前被搶占的進(jìn)程被保存的上下文,3將控制傳遞給這個(gè)新恢復(fù)的進(jìn)程。
?
7進(jìn)程控制和信號(hào)
1.進(jìn)程控制
?a.獲取進(jìn)程號(hào)(進(jìn)程有唯一的進(jìn)程號(hào) 正數(shù) ID/PID)
getpid;
b.創(chuàng)建進(jìn)程和終止進(jìn)程
程序員角度分三種
1運(yùn)行:進(jìn)程在cpu運(yùn)行或等待運(yùn)行且最終被內(nèi)核調(diào)度。
2停止:進(jìn)程的執(zhí)行被掛起,且無(wú)觸發(fā)條件不會(huì)被調(diào)度。
3終止:永遠(yuǎn)停止了,如收到一個(gè)信號(hào)終止了進(jìn)程,或調(diào)用exit;
4創(chuàng)建:fork、vfork;
fork:調(diào)用一次返回兩次,和父進(jìn)程用相同的地址空間,與父進(jìn)程并發(fā)執(zhí)行,與父共享文件,pid不一樣;
c.回收子進(jìn)程
一個(gè)終止的進(jìn)程若沒(méi)有被父進(jìn)程回收,會(huì)變成僵死進(jìn)程,仍然會(huì)占用內(nèi)存空間,直到被回收
若其父進(jìn)程先終止,則另init進(jìn)程收養(yǎng)、回收。init進(jìn)程pid為1,是所有進(jìn)程的祖先。
d.進(jìn)程的休眠
sleep pause;
?
2.信號(hào)
a.一次軟件形式的異常,一個(gè)信號(hào)就是一條消息,他通知進(jìn)程系統(tǒng)中發(fā)生了一個(gè)某種類型
的事件。
底層的硬件異常是由內(nèi)核異常處理程序處理,一般情況對(duì)用戶而言是不可見(jiàn)的,但信號(hào)提供
了一種機(jī)制告訴用戶進(jìn)程系統(tǒng)發(fā)生了什么樣的異常。
b.發(fā)生信號(hào)的原理:內(nèi)核改變目的進(jìn)程的上下文中某個(gè)狀態(tài)來(lái)傳遞一個(gè)信號(hào)給目的進(jìn)程;
(收發(fā)信號(hào)可簡(jiǎn)理解為:上下文中存與取)
接收信號(hào)后常見(jiàn)的信號(hào)處理行為有以下幾種:
1進(jìn)程終止:SIGKILL
2進(jìn)程終止并轉(zhuǎn)儲(chǔ)內(nèi)存
3進(jìn)程停止(掛起)知道被SIGXONT信號(hào)重啟
4進(jìn)程忽略該信號(hào)
c.進(jìn)程組的概念,每個(gè)進(jìn)程都屬于一個(gè)進(jìn)程組,且父子進(jìn)程同屬于一個(gè)進(jìn)程組。
d.阻塞和解除阻塞
隱式阻塞:阻塞任何與當(dāng)前正在處理的信號(hào)類型的待處理的信號(hào)。
顯式阻塞:明確的阻塞和解除阻塞選定的信號(hào)。
e.非本地跳轉(zhuǎn)
一種用戶級(jí)異常控制流,他可以將控制直接從一個(gè)函數(shù)轉(zhuǎn)移到另一個(gè)當(dāng)前正在執(zhí)行的函數(shù)而不用通過(guò)函數(shù)棧機(jī)制
8.進(jìn)程間的通信
指在不同的進(jìn)程之間傳播和交換信息
常見(jiàn)的通信手段:
1、管道及有名管道 :管道用于有親緣關(guān)系進(jìn)程間的通信,有名管道克服了管道沒(méi)有名字的限制,因此,有名管道
可用于無(wú)親緣關(guān)系進(jìn)程間通信。
2、信號(hào):用于通知接受進(jìn)程有某種事件發(fā)生,除了用于進(jìn)程間通信外,進(jìn)程還可以發(fā)信號(hào)給進(jìn)程本身。
3、消息隊(duì)列:是消息的鏈表,存放在內(nèi)核中,并由消息隊(duì)列標(biāo)志符標(biāo)示。克服了信號(hào)傳輸信息少,管道只能承載無(wú)格式字節(jié)
及緩存區(qū)大小受限等問(wèn)題;
4信號(hào)量:信號(hào)量是一個(gè)計(jì)數(shù)器,可以用來(lái)控制多個(gè)進(jìn)程對(duì)共享資源的訪問(wèn);
5共享內(nèi)存:多個(gè)進(jìn)程可以訪問(wèn)同一塊內(nèi)存空間,是最快的ipc形式,一般結(jié)合信號(hào)量使用;
6套接字:更一般的進(jìn)程間通信機(jī)制,可以完成本機(jī)或者跨機(jī)器的進(jìn)程通信;
?
9.進(jìn)程間信號(hào)量的控制
?信號(hào)量是一個(gè)計(jì)數(shù)器,是一個(gè)具有非負(fù)整值的全局變量,能做如下兩個(gè)操作:
P(s):如果s為非零,那么P將s減1,并且立即返回。如果s為零,那么就掛起這個(gè)線程,直到
s變?yōu)榉橇?#xff0c;而一個(gè)V操作會(huì)重啟這個(gè)線程。重啟后P操作將s減1,并將控制返回給調(diào)用者。
V(s):V操作將s加1,如果有任何線程阻塞在P操作等待s變成非零,那么V操作會(huì)重啟這些
線程中的一個(gè),然后該線程將s減1,完成它的P操作。
?
10.信號(hào)量
信號(hào)量是一個(gè)特殊的變量,程序?qū)ζ湓L問(wèn)都是原子操作,且只允許對(duì)它進(jìn)行P和V操作,最簡(jiǎn)單
的信號(hào)量是只能取0和1的變量,這也是信號(hào)量最常用的一種形式,叫做二進(jìn)制信號(hào)量。而可以取多個(gè)
常亮的信號(hào)量被稱為通用信號(hào)量;
?
11 各種并發(fā)編程模式
概念:如果邏輯控制流在時(shí)間上有重疊,那它們就是并發(fā)的;
場(chǎng)景:
1訪問(wèn)慢速I/O設(shè)備
2與人交互
3推遲工作以降低延遲
4服務(wù)多個(gè)網(wǎng)絡(luò)客戶端
5在多核機(jī)器上并行計(jì)算
三種并發(fā)編程模式
1基于進(jìn)程的并發(fā)編程
每個(gè)邏輯控制流都是一個(gè)進(jìn)程,由內(nèi)核來(lái)調(diào)度和維護(hù)
優(yōu)缺點(diǎn):
優(yōu)點(diǎn):共享文件表,不共享用戶空間,更加的安全。
缺點(diǎn):開(kāi)銷大,共享信息困難,要使用顯式的IPC
2基于I/O多路復(fù)用的并發(fā)編程
基本的思想就是使用select函數(shù),要求掛起進(jìn)程,只有在一個(gè)或多個(gè)I/O事件發(fā)生后,
才將控制返回給應(yīng)用程序;
I/O多路復(fù)用可以用做并發(fā)事件驅(qū)動(dòng)程序的基礎(chǔ)。
優(yōu)缺點(diǎn):
優(yōu)點(diǎn):程序員能更好的控制程序,共享數(shù)據(jù)簡(jiǎn)單
缺點(diǎn):編碼復(fù)雜,并且程度越小,復(fù)雜度越高;
3基于線程并發(fā)模型
概念:線程就是運(yùn)行在進(jìn)程上下文中的邏輯流,線程也由內(nèi)核調(diào)度,每個(gè)線程都有自己的線程上下文,包括線程ID、棧、棧指針、程序計(jì)數(shù)器、條件嗎和通用目的寄存器。
線程的切換比進(jìn)程快很多,線程是對(duì)等的,任何線程都可以訪問(wèn)共享虛擬內(nèi)存的任何位置。
分離線程
線程要么是可結(jié)合的,要么是可分離的,區(qū)別:
1可結(jié)合線程:可以被其他線程回收和殺死,被回收之前,它所占有的資源不會(huì)被釋放
2可分離線程:不可以回收不可以殺死,它的內(nèi)存資源在其終止時(shí)自動(dòng)釋放,默認(rèn)創(chuàng)建的都是可結(jié)合線程;
?
12?共享變量和線程同步
?1)線程內(nèi)存模型:
每個(gè)線程都有自己獨(dú)立的線程上下文、包括線程ID、棧棧指針、程序計(jì)數(shù)器、條形碼和通用目的寄存器。
線程與其他線程共享進(jìn)程上下文的剩余部分。包括整個(gè)用戶虛擬地址空間。
2)將變量映射到內(nèi)存
全局變量:定義在函數(shù)之外的變量,運(yùn)行時(shí),全局變量只有一個(gè)實(shí)例,任何線程都可以引用。
本地自動(dòng)變量:定義在函數(shù)內(nèi),但沒(méi)有用static屬性的變量,運(yùn)行時(shí)每個(gè)線程的棧都包含它自己的
所有本地自動(dòng)變量實(shí)例。
本地靜態(tài)變量:函數(shù)內(nèi)部用static屬性的變量,運(yùn)行時(shí)只有一個(gè)實(shí)例。
3)共享變量
我們說(shuō)一個(gè)變量v是共享的,當(dāng)且僅當(dāng)它的一個(gè)實(shí)例被一個(gè)以上的線程引用。如果只有一個(gè)線程引用就
不是共享的。共享變量是簡(jiǎn)單的,但這種共享方式會(huì)引來(lái)同步錯(cuò)誤,因?yàn)榫€程之間的運(yùn)行是競(jìng)爭(zhēng)關(guān)系,
沒(méi)辦法確認(rèn)進(jìn)程運(yùn)行的順序,為了解決這種錯(cuò)誤,可以使用信號(hào)量來(lái)對(duì)共享資源加鎖,使其確定線程對(duì)該
變量的互斥訪問(wèn)。
4)線程同步
確保每個(gè)線程在執(zhí)行它的臨界區(qū)中的指令時(shí),擁有對(duì)共享變量的互斥訪問(wèn)。
通過(guò)對(duì)二元信號(hào)量的使用(二元信號(hào)量也稱為互斥鎖),對(duì)共享資源進(jìn)行加鎖,使得每次只會(huì)有一個(gè)
線程能夠訪問(wèn),直到訪問(wèn)完成,其他線程才能訪問(wèn),這樣就能對(duì)資源的互斥旺旺,達(dá)到線程同步。
13 其他并行問(wèn)題
1)線程安全:如果一個(gè)函數(shù)被稱為線程安全的,那 當(dāng)且僅當(dāng)被多個(gè)并發(fā)線程反復(fù)地調(diào)用時(shí),它會(huì)一直產(chǎn)生正確的結(jié)果。
四種線程不安全函數(shù):
1不保護(hù)共享變量的函數(shù)
2保持跨越多個(gè)調(diào)用的狀態(tài)的函數(shù)。
3返回指向靜態(tài)變量的指針函數(shù)。
2)可重入性
有一類重要的線程安全函數(shù),叫可重入函數(shù),當(dāng)它們被多個(gè)線程調(diào)用時(shí),不會(huì)引用任何共享數(shù)據(jù),盡管
線程安全和可重入不等價(jià),可重入函數(shù)屬于線程安全函數(shù);
顯式可重入函數(shù):不依賴調(diào)用者,所有的數(shù)據(jù)引用都是本地自動(dòng)棧變量,且參數(shù)是傳值傳遞的(不是指針);
隱式可重入函數(shù):形參可以使指針,小心的傳遞指向非共享數(shù)據(jù)的指針;
3)LINUX提供不安全的可重入版本(安全)函數(shù)名多以_r結(jié)尾;
4)競(jìng)爭(zhēng):當(dāng)程序的結(jié)果依賴一個(gè)線程要在另一個(gè)線程達(dá)到y(tǒng)點(diǎn)前到達(dá)它的控制流中的x點(diǎn)時(shí),就會(huì)產(chǎn)生競(jìng)爭(zhēng);
5)死鎖:一個(gè)線程阻塞了,等待一個(gè)永遠(yuǎn)不會(huì)為真的條件。
?
?
--
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
---------------------
?
總結(jié)
- 上一篇: 切木头之二分法启示
- 下一篇: Algs4-1.5.1使用quick-f