第9章 Windows下的動態(tài)鏈接

9.1

dll介紹

dll(Dynamic Link Library)跋理,動態(tài)鏈接庫择克,它和exe基本上一樣,只不過它的pe文件頭中的符號表標(biāo)明該文件是dll而不是exe前普。

dll文件的后綴名不僅是dll還可以是ocx和cpl肚邢。

dll設(shè)計(jì)的目的不同于共享對象,它關(guān)注的是軟件工程中的模塊化設(shè)計(jì)思想拭卿,想要做到高內(nèi)聚低耦合骡湖,它方便了軟件的升級和維護(hù)。

9.1.2基地址和RVA

exe文件里面也有基地址和RVA(Relative Virtual Address峻厚,相對虛擬地址)勺鸦。

對于dll來說它的基地址有一個默認(rèn)值,如果這個默認(rèn)值被其他模塊占用了目木,它就找個別的地方裝載。

9.1.3

dll共享數(shù)據(jù)段

dll中有些數(shù)據(jù)是共享的懊渡,有些是進(jìn)程私有的刽射。

按照這個區(qū)別劃分的話,就可以把數(shù)據(jù)段分成兩種剃执。

不過由于各進(jìn)程共同訪問公共數(shù)據(jù)段誓禁,如果某一進(jìn)程惡意破壞數(shù)據(jù),其他進(jìn)程也會受到影響肾档,這存在一定的安全隱患摹恰。

9.1.4

dll的簡單例子

ELF中的符號默認(rèn)都是可以導(dǎo)入導(dǎo)出的,所謂導(dǎo)出就是指可以被別的模塊調(diào)用怒见,導(dǎo)入就不解釋了俗慈,而DLL中的符號需要指定才能導(dǎo)入導(dǎo)出。

__declspec(dllexport)用來指定導(dǎo)出符號遣耍,__declspec(dllimport)用來指定導(dǎo)入符號闺阱。

另外,還可以用def文件中的IMPORT和EXPORTS段來聲明符號的導(dǎo)入和導(dǎo)出舵变。

如果是C語言的符號規(guī)范酣溃,你必須在符號的定義之前加上external

“C”。

9.1.7使用模塊定義文件

就是前面提到的def文件了纪隙,它的好處有如下幾點(diǎn):

1赊豌、能夠控制導(dǎo)出符號的符號名。原來__cdecl绵咱、__stdcall碘饼、__fastcall都是msvc中的函數(shù)規(guī)范啊。編譯器會對源碼中的符號進(jìn)行修飾,經(jīng)過修飾的符號變得和環(huán)境中的符號不兼容派昧,不便于維護(hù)和使用黔姜,于是采用def文件對導(dǎo)出符號進(jìn)行重命名。

2蒂萎、它可以控制一些鏈接的過程秆吵。它還可以控制輸出文件名、段的屬性五慈、堆棧大小纳寂、版本號等。

9.1.8

DLL顯示運(yùn)行時鏈接

即泻拦,運(yùn)行時加載毙芜。

Windows提供了3個API:

1、LoadLibrary裝載一個DLL進(jìn)進(jìn)程地址空間争拐。

2腋粥、GetProAddress查找某個符號的地址。

3架曹、FreeLibrary用來卸載某個已經(jīng)加載的模塊隘冲。

9.2符號導(dǎo)出導(dǎo)入表

9.2.1導(dǎo)出表

Windows下的PE文件的導(dǎo)出符號全部集中在導(dǎo)出表中,供其他PE文件調(diào)用绑雄,它提供的是一種符號與地址的映射關(guān)系展辞。

導(dǎo)出表是個DataDirectory的結(jié)構(gòu)體數(shù)組,名字叫做IMAGE_EXPORT_DIRECTORY万牺,被定義在Winnt.h中罗珍。

DataDirectory中最后三項(xiàng)EAT(Export Address Table)、Name

Table脚粟、Name

Ordinal Table分別代表導(dǎo)出地址表覆旱、符號名表、名字序號對應(yīng)表核无。

導(dǎo)出地址表存放的是個符號的相對虛擬地址通殃。

符號名表存放的是導(dǎo)出符號的名字。

名字序號對應(yīng)表存放的是函數(shù)的序號和函數(shù)名的對應(yīng)關(guān)系厕宗。

函數(shù)序號存在的意義在于節(jié)省空間和查找方便画舌,壞處是函數(shù)變化了序號也要跟著變化。導(dǎo)出函數(shù)一定有序號但可以沒有函數(shù)名已慢。

9.2.2

EXP文件

在創(chuàng)建DLL時會產(chǎn)生一個EXP曲聂,EXP中的.edata存放的是導(dǎo)出表。EXP會與其他目標(biāo)文件一樣一起鏈接生成DLL并且成為導(dǎo)出表佑惠。

9.2.4導(dǎo)入表

來自于DLL和其他可執(zhí)行文件中的符號會存儲在導(dǎo)入表中朋腋。

導(dǎo)入表是一個IMAGE_EXPORT_DIRECTORY結(jié)構(gòu)體數(shù)組齐疙。

IMAGE_EXPORT_DIRECTORY中的FirstThunk指向?qū)氲刂窋?shù)組(Import

Address Table,IAT)旭咽,每個IAT對應(yīng)一個被導(dǎo)入的符號贞奋。

延遲載入:DLL也支持延遲裝載,它是通過特殊的樁代碼實(shí)現(xiàn)的穷绵。

9.2.5導(dǎo)入函數(shù)的調(diào)用

PE DLL的代碼段并不是地址無關(guān)的轿塔。

PE采用了重定基地址的方法來解決模塊裝載時進(jìn)程空間中地址沖突的問題。

__declspec(dllimport)的作用是使編譯器能夠區(qū)分函數(shù)是從外部導(dǎo)入的還是模塊內(nèi)部定義的仲墨。

同一個導(dǎo)出函數(shù)會產(chǎn)生兩個符號的定義勾缭,一個指向該函數(shù)的樁代碼,一個指向該函數(shù)在IAT中的位置目养。

用__declspec(dllimport)來聲明導(dǎo)入函數(shù)時會在導(dǎo)入函數(shù)前面加上__imp__以確保跟庫中的函數(shù)符號正確鏈接俩由。

9.3

DLL優(yōu)化

DLL本身的代碼段和數(shù)據(jù)段并不是地址無關(guān)的。

一旦DLL的基址被占用癌蚁,它就必須被重定位幻梯,這需要時間開銷。

雖然在DLL中采用二分查找法進(jìn)行符號字符串的比較和查找努释,但是由于符號眾多礼旅,因此這也是一項(xiàng)非常耗時的工作。

以上是影響DLL性能的兩個問題洽洁。

9.3.1重定基地址

在裝載DLL時發(fā)生了地址沖突,就必須對每個絕對地址的引用都進(jìn)行重定位菲嘴。

重定位的過程很簡單就是在原來的地址基礎(chǔ)上加上一個偏移量饿自,但是這是對所有需要重定位的絕對地址而言的。

PE文件的重定位信息都放在reloc段中龄坪。

一般來講exe文件是不會發(fā)生重定位的昭雌,因?yàn)樗偸潜坏谝粋€裝載。

而DLL則是動態(tài)裝載所以它的裝載地址可能被占用健田。

DLL文件中代碼段的訪問比ELF更加快速烛卧,是一種空間換時間的優(yōu)化策略,因?yàn)樗總€進(jìn)程都有一個副本妓局。

確切地說它是裝載時重定位基址总放。

DLL的裝載和地址順序是一樣的。

DLL的基地址是可以手動指定的好爬,不然老是重定位多麻煩啊局雄,VC提供這種功能。

9.3.2序號

一個導(dǎo)出的函數(shù)符號可以沒有函數(shù)名存炮,但是絕對不能沒有序號炬搭。

序號表示導(dǎo)出函數(shù)在導(dǎo)出表中的位置蜈漓。

內(nèi)部使用的函數(shù)一般只有序號沒有函數(shù)名。

Windows API雖然函數(shù)名是不變的宫盔,但是序號總是在變化的融虽。

序號可以通過def文件指定。

凡是涉及到PE文件的查找的地方用的都是二分查找法灼芭。

9.3.3導(dǎo)入函數(shù)綁定

由于無論如何導(dǎo)入導(dǎo)出的符號關(guān)系都會被重新解析有额,而且每次解析完畢后它們被裝載的內(nèi)存地址都相同,那么這個解析過程就是浪費(fèi)姿鸿。

針對這種浪費(fèi)采取的優(yōu)化策略就叫做DLL綁定谆吴,具體方法是把這些導(dǎo)入的符號保存在模塊的導(dǎo)入表中每次只需查表即可。

INT(Import Name Table)苛预,導(dǎo)入名稱表句狼,把符號運(yùn)行時的目標(biāo)地址寫到INT中。

DLL更新和重定基址可能導(dǎo)致DLL綁定地址失效热某。

針對DLL更新腻菇,Windows會核對裝載的DLL與綁定時的DLL版本是否相同,還有該DLL是否發(fā)生過重定基址昔馋,如果都沒有那就直接查表筹吐。

DLL綁定過程可以發(fā)生在安裝的時候,可能改變可執(zhí)行文件本身從而導(dǎo)致可執(zhí)行文件的校驗(yàn)和變化秘遏。這對于一些經(jīng)過加密的和數(shù)字簽名的程序來說可能會有問題丘薛。

9.4

C++與動態(tài)鏈接

Linux下的共享庫絕大多數(shù)都是用C語言寫的,這是因?yàn)镃++編寫的庫比C語言編寫的庫要復(fù)雜得多邦危,而且由于C++沒有二進(jìn)制級別的規(guī)定只有語法級別的洋侨,所以也為共享庫的更新帶來了不便。

C++帶來的麻煩主要表現(xiàn)在以下幾個方面:

1倦蚪、內(nèi)存釋放過程復(fù)雜希坚,不好把握。因?yàn)椴煌腄LL和EXE使用不同的堆陵且。

2裁僧、所謂的更新只不過是簡單的覆蓋。

3慕购、正是由于舊版DLL被覆蓋聊疲,如果新版程序運(yùn)行出錯,舊版程序也運(yùn)行出錯沪悲,那就悲劇了售睹。

為了解決程序開發(fā)中遇到的兼容性問題,微軟推出了組件對象模型(COM可训,Component

Object Model)昌妹。

P300列出了幾點(diǎn)用C++編寫DLL時應(yīng)該遵循的原則捶枢。

9.5

DLL HELL

早期Windows中的DLL文件使用范圍大,更新也頻繁飞崖,而且還缺乏版本控制機(jī)制烂叔,所以DLL不兼容的情況在早期Windows下特別嚴(yán)重,史稱DLL噩夢固歪。

導(dǎo)致DLL

HELL發(fā)生的3個原因見P301中所說明的蒜鸡。

解決DLL

HELL的方法:

1、由于DLL HELL是由DLL引起的牢裳,即動態(tài)鏈接引起的逢防,所以最徹底的解決辦法是不使用動態(tài)鏈接,而使用靜態(tài)鏈接蒲讯。

2忘朝、避免DLL覆蓋。這個可以通過Windows的文件保護(hù)機(jī)制實(shí)現(xiàn)判帮。

3局嘁、避免DLL沖突。它主要是針對不同應(yīng)用程序依賴相同DLL的不同版本的問題晦墙,解決辦法是讓每個應(yīng)用程序悦昵。

.NET下的程序集包括兩種類型應(yīng)用程序集和庫程序集,前者是指EXE可執(zhí)行文件晌畅,后者是指DLL動態(tài)鏈接庫但指。

由于程序集包括一個或多個文件所需要一個清單來描述,這個清單叫做Manifest文件抗楔,它就是描述了程序及的各種屬性信息棋凳,其本質(zhì)是一個XML文件。

在Windows

XP以前的版本中Manifest就是個擺設(shè)谓谦,這以后的Windows版本在執(zhí)行可執(zhí)行文件時首先要讀取Manifest內(nèi)容獲取所需的DLL文件列表,然后Windows再根據(jù)DLL的Manifest文件去掉用DLL贪婉。

CRT(C Run-Time Library):C語言運(yùn)行庫反粥。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市疲迂,隨后出現(xiàn)的幾起案子才顿,更是在濱河造成了極大的恐慌,老刑警劉巖尤蒿,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郑气,死亡現(xiàn)場離奇詭異,居然都是意外死亡腰池,警方通過查閱死者的電腦和手機(jī)尾组,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門忙芒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人讳侨,你說我怎么就攤上這事呵萨。” “怎么了跨跨?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵潮峦,是天一觀的道長。 經(jīng)常有香客問我勇婴,道長忱嘹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任耕渴,我火速辦了婚禮拘悦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘萨螺。我一直安慰自己窄做,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布慰技。 她就那樣靜靜地躺著椭盏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吻商。 梳的紋絲不亂的頭發(fā)上掏颊,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音艾帐,去河邊找鬼乌叶。 笑死,一個胖子當(dāng)著我的面吹牛柒爸,可吹牛的內(nèi)容都是我干的准浴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捎稚,長吁一口氣:“原來是場噩夢啊……” “哼乐横!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起今野,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤葡公,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后条霜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體催什,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年宰睡,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒲凶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片气筋。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖豹爹,靈堂內(nèi)的尸體忽然破棺而出裆悄,到底是詐尸還是另有隱情,我是刑警寧澤臂聋,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布光稼,位于F島的核電站,受9級特大地震影響孩等,放射性物質(zhì)發(fā)生泄漏艾君。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一肄方、第九天 我趴在偏房一處隱蔽的房頂上張望冰垄。 院中可真熱鬧,春花似錦权她、人聲如沸虹茶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝴罪。三九已至,卻和暖如春步清,著一層夾襖步出監(jiān)牢的瞬間要门,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工廓啊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留欢搜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓谴轮,卻偏偏與公主長得像炒瘟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子第步,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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