日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

链接器相关的一些基本问题

發布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 链接器相关的一些基本问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鏈接器相關的一些基本問題

  學習或者了解鏈接器,有一些基本的問題需要關心:鏈接器做些什么;鏈接器和體系結構;程序是怎樣生成的。下面做簡要介紹。

鏈接器做些什么

  鏈接器之所以存在或者產生,基本上是由于程序開發的模塊化。這里講的模塊,主要是編譯概念上的模塊,通常他們按照功能劃分,比如一個.c或者.cpp文件就是一個編譯單元,就是一個模塊,編譯后就產生一個.o目標文件。為了最終生成一個可執行文件、靜態庫或者動態庫,就需要把各個編譯單元按照特定的約定組合到一起。這里特定的約定指的就是“目標文件格式”,它定義了目標文件、庫文件和可執行文件的格式,這里組合這一過程就叫做鏈接。
  一個編譯模塊中,通常是函數的定義和全局數據的定義,數據類型的定義通常在頭文件中,編譯時會被包含在編譯模塊中。函數和數據由符號來標識,一般符號有全局和靜態之分,全局符號可以被其他模塊引用,而靜態符號只能在本模塊中引用。編譯各個模塊時,編譯器會解析該模塊。重要的一項工作就是建立符號表,符號表中包含了本模塊有哪些符號可以被其他模塊引用(導出符號),還包括本模塊引用(導入符號,即未定義符號)、但在其他模塊中定義的符號。每一個符號都關聯一個地址,這個地址指明了該符號在本模塊中的偏移地址(通常是一個從0開始的地址)。
  鏈接器在鏈接過程中,會掃描各個模塊的符號表,得到一個“全局符號表”,鏈接器由此決定一個符號在哪里被定義,在哪里被引用。并且,將符號引用處替換為定義處的地址,這一過程就叫做符號解析。
  鏈接器的一項終極目標就是生成可執行文件。通常,可執行文件和普通目標文件的重要區別就是地址空間的使用。主流操作系統中,可執行文件都是基于虛擬地址空間的,即每個可執行文件都有相同且獨立的地址空間,并且文件中各個段(代碼段,數據段,以及進程空間中的堆棧段)都有相似的布局。而普通目標文件卻使用從零開始的地址空間,這樣一來,模塊M中的符號m就可能和模塊N中的符號n擁有“相同”的地址。在鏈接器鏈接各個模塊時,會從各個模塊中“提取”類型相同的段進行合并,并將合并后的段寫入可執行文件中。這一過程被稱為存儲空間的分配。值得一提的是,棧、堆以及未初始化的數據這些“運行時”需要的空間不會在可執行文件中占據磁盤空間,但它們占用相應的地址空間。
  由于存在上述“合并”過程,前面提到的符號解析就涉及到另外一個過程:重定位。由于各個模塊中的函數/數據地址會被重新排放,那么對這些符號的引用也必須被相應地調整。這一調整過程被稱作重定位。
  符號解析,存儲空間分配,還有重定位,這三個過程是一個有機的整體,是“同時”進行的,且這三個過程也是模塊化所帶來的必須要解決的問題。

鏈接器和體系結構

  在我們編寫普通應用程序時,不需要過多的關系體系結構的問題,但對于鏈接器學習者/編寫者來說,相當大的工作都必須圍繞體系結構展開,比如目標平臺的ABI,內存地址,指令格式,尋址方式等等,下面做大致介紹。
  一個體系結構的ABI,即二進制程序接口,主要包括硬件和操作系統兩個層面。內存字長,對齊方式,子程序調用時的約定(參數傳遞方式,返回值傳遞方式),系統調用如何進行,目標文件格式等等,都屬于ABI的范疇,都是鏈接器工作時要密切關注的問題。
  另外,多字節數據的字節序也是鏈接器需要考慮的。字節序是關于如何使用線性的連續字節來表示多字節數據的問題,有Little-endian和Big-endian兩種字節序。小端序是指將多字節數據的低權重字節放在內存的低地址處,大端序則正好相反。直觀講,從內存的低地址向高地址方向看,先看到多字節數據的低權重字節的就是小端序,否則就是大端序。至于為什么會存在兩種字節序,兩者有何優劣,我覺得這只是個“個人喜好”問題,就好象剝雞蛋先磕破哪一頭,蹲廁所時臉里還是臉朝外一樣,事實上,直到前些天,我才親眼看到,真的是有“茅房拉屎臉朝內”的人的。
  指令格式和尋址方式也會影響鏈接器的工作,因為在符號重定位的時候,鏈接器需要修改指令中操作數部分,所以需要知道每種指令的指令格式及尋址方式,以便對指令做出適當的調整。

程序是怎樣生成的

  事情漸漸明了了,編譯器前端對語言進行詞法、語法分析,建立語法樹,編譯器后端在語法樹的基礎上針對特定的平臺生成指令,并按照特定的格式輸出到磁盤中的目標文件。鏈接器按照前面所說的過程生成最終的可執行文件或程序庫。(這里的程序庫特指動態庫,因為靜態庫只是目標文件的簡單集合,理論上不需要鏈接器的參與)本文只針對鏈接器進行簡單的討論,關于編譯器的功能和相關原理,有大量的資料可以參考。

目標文件格式

  目標文件格式是指令、數據在磁盤中存儲形式的一種約定。它描述了指令、數據的存儲格式和布局,并且針對不同類型的文件(普通目標文件,可執行文件,動態庫)有不同描述側重點。另外它還描述了一些供外部程序使用的元信息,例如普通目標文件中的符號表的內容和組織形式,待重定位符號的信息;可執行文件中各個段的信息,程序的入口點(程序從何處開始執行),哪些符號需要在運行時解析,這些符號包含在哪些動態庫中,以及解析這些庫需要哪種動態鏈接器等等;動態庫為了實現同時被多個進程鏈接需要什么樣的組織形式,本身又引用了其他動態庫的哪些符號等等。通常,不同的平臺都會有自己的目標文件的格式標準:

  • COM:DOS最初采用的一種非常簡單的格式,除了指令、數據之外,基本不包含其他信息。
  • PE:Windows當前采用的目標格式,繼承自COFF,是一種主流的現代目標格式,相比COM有更強大的功能支持。
  • a.out:最初UNIX平臺采用的目標格式,簡單且功能強大,但對于C++這樣的高級語言支持不足。
  • ELF:當前Linux/Unix平臺采用的主流格式,繼承自a.out,且對高級語言支持很友好。

  除了ABI,目標格式的不同,也是在一種操作系統下編譯的程序無法在另一種操作系統中執行的原因。

程序庫

  終于到庫了,研究庫很有趣,也相當實用。概念上,庫可以分為靜態庫,動態庫,且這兩種庫都可以實現為“共享庫”,但在實現上,靜態共享庫由于需要考慮態度的問題、實現太過復雜且得不償失,現實中很少有這種類型的庫。所以,應用中只存在兩種庫:靜態庫和動態共享庫,下面分別做簡要介紹,關于在Linux中如何創建這兩種庫,可以參考我之前寫的一篇博客,或者其他更詳盡更優秀的資料。

靜態庫

  在功能特性上,靜態庫是指這樣一種庫,在鏈接時,其中被引用的代碼、數據被“復制”到引用該庫的程序中。在格式上,靜態庫十分簡單,他是普通目標文件的集合,是一種簡單的拼接。事實上,Linux平臺下靜態庫.a文件使用獨立的歸檔工具ar建立,為了使鏈接器能夠有效地查找庫中包含的各個目標文件以及符號,經常還需要一個叫做ranlib的工具在.a文件中建立索引。
  在鏈接時,鏈接器想普通目標文件一樣使用靜態庫,僅僅多了在庫中查找符號及對應目標文件的過程。

動態鏈接庫

  動態鏈接庫和靜態庫差異較大,Linux平臺,它由ELF格式直接支持。但由于共享庫的特殊性,它需要一些特殊特性的支持:
  PIC(Position Independent Code),位置無關代碼。動態共享庫需要在運行時動態地加載到內存,為了在各個進程中調用共享庫中的代碼和數據,就需要將該庫映射到不同進程的進程空間。由于各個進程的地址空間使用情況不盡相同,很難將共享庫映射到各進程相同的位置。這樣一來,就對共享庫的代碼提出了挑戰,它需要能夠在不同的地址區間上都正確的執行。位置無關代碼就是因此而提出的。
  位置無關代碼的基本思想是這樣的:將共享中對絕對地址的引用轉化為相對地址的形式。對于函數調用,實現起來很簡單,因為代碼是只讀的,指令間的相對地址也是固定的,只需要將函數調用轉化會相對地址即可。但對于數據的引用就復雜很多了,由于各個進程都需要訪問共享庫中的數據,而這些進程通常是毫無關聯的,一個進程對共享庫數據的修改不應該被其他進程看到。一種好的方法就是讓各個進程都擁有自己的一份數據拷貝。但這又引出一個問題,共享庫是被動態映射的,數據空間也只能在映射時才需要分配,那么在共享庫代碼中如何引用這些數據,以達到不同進程使用相同的代碼訪問不同的數據呢?
  于是另外一種結構被引入了,即GOT(Global Offset Table),全局偏移量表。它的基本思想也是相對地址引用。在共享庫的數據段加入GOT,GOT的表項保存各個數據的地址。由于共享庫中指令和數據段的相對地址在鏈接后是固定的,這樣在指令中就可以使用相對地址來找到GOT的起始地址,然后根據各個數據在GOT的偏移量來找到其對應的地址。而該地址是在共享庫被映射到進程空間時,由動態鏈接器在相應的進程空間中分配并設置的。
  接下來的問題就是,進程中如何調用共享庫中的代碼呢?ELF使用一種延遲加載的方法,即當進程調用共享庫中一個函數時,才解析該函數的地址,且只有第一次才解析,第一次解析之后的調用就不會被再次解析,而是將之前解析到的地址保存下來。這里又引入一種機制,叫做PLT(Procedure Linkage Table),它和GOT一起(使用共享庫的進程也有一個GOT)引入了一個函數調用的間接層。
  類似共享庫的GOT,進程的GOT表項保存了本進程引用的共享庫中的函數地址,但在第一次對該函數的調用之前,該表項保存的并不是函數的地址,而是指向PLT中一個指令的地址。為了方便說明問題,假設進程中main函數引用了libmath.so中的函數add,那么PLT大致是這個樣子的,

1 2 3 4 5 6 7 8 9 10 11 12 13 .plt0:0x080483d0: pushl 0x8049ff80x080483d6: jmp *0x8049ffc ... add@plt:0x080483e0 <+0>: jmp *0x804a0000x080483e6 <+6>: push $0x00x080483eb <+11>: jmp 0x80483d0 ... main: ...0x080484ec <+24>: call 0x80483e0 <add@plt> # 對add函數的調用 ...

  第十二行對add函數的調用跳轉到第五行,這是一條jmp指令,0x804a000是它的地址操作數,該地址即是add在GOT中的地址項,最初該地址處保存的地址是0x080483e6,即jmp指令的下一條push指令。于是最初jmp指令執行后沒有任何效果,直接執行下一條指令。push指令將add在重定位項的索引入棧,通過該重定位項可以得到add符號本身(即字符串add)。然后又是一條jmp指令它跳轉到第二行,又是一個push指令,接下來又是jmp指令,這個jmp指令也使用了GOT中的一個表項,該表項存儲的是動態鏈接器(ld.so)的加載/解析函數。在解析函數中,查找add符號在共享庫中的地址,將該地址填入add對應的GOT表項,然后跳轉至add函數開始執行。到下一次調用add函數,第五行的jmp指令就直接跳轉到add函數了。
  動態鏈接基本就是這個過程了。在這個過程中有許多有意思的指令,將棧玩弄于鼓掌,像變魔術一樣,有興趣的話可以使用gdb等相關工具調試一下。

一些工具

  玩弄二進制,很多實用工具是離不了的,最重要的就是GNU Binutils二進制工具鏈了。包括查看ELF文件信息的readelf,對目標文件、可執行文件、共享庫、core內存轉儲文件等反匯編的objdump,重量級的調試器gdb,查看共享庫使用情況的ldd等等。

一些參考資料

  了解鏈接器工作原理,現成的資料并不多,《Linkers and Loaders》算是經典了,中文版也可以買得到,翻譯得還算中規中矩。另外,《程序員的自我修養:鏈接、裝載與庫》寫的很淺顯,不錯的一本書。
  為了更好的理解鏈接器,必須對ELF的細節有所了解,Executable and Linkable Format這份文檔可以參考。
  研究二進制,匯編知識是必須的,如果是Linux平臺,了解些GNU 匯編(AT&T匯編)是再好不過了,不過講解GNU匯編的資料更是少上加少,布魯姆的《匯編語言程序設計》雖然內容不多,但對非專業匯編程序員也足夠用了,這本書是有英文電子版的。
  有了相關工具和入門資料,剩下的就是折騰了。
  最后,附上之前做的幻燈片,就像這篇文章一樣,臭長,枯燥

總結

以上是生活随笔為你收集整理的链接器相关的一些基本问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文无码一区二区三区在线观看 | 午夜影院免费视频 | 能看的av | 香蕉网久久 | 欧美色图网站 | 亚洲av少妇一区二区在线观看 | 入禽太深免费视频 | 日韩黄色在线 | 欧美第三页| 国产一区不卡在线 | 91精品亚洲 | 综合伊人 | 国产精品久久久久久av | 最新色站| 性欧美成人播放77777 | 鬼灭之刃柱训练篇在线观看 | 国产午夜精品在线 | 色版视频在线观看 | 五月天免费网站 | 大又大又粗又硬又爽少妇毛片 | 日本xxxx裸体xxxx | 超黄网站在线观看 | 一道本在线观看视频 | 久久成人久久 | 国产一级做a爱片久久毛片a | 久久综合影视 | 午夜爱爱网 | a人片| 精品久久国产视频 | 男人天堂2014 | 国产哺乳奶水91在线播放 | 在线观看视频毛片 | 超碰在线cao | 一级黄色片在线 | 亚洲一二三四视频 | 国产18在线观看 | 韩国91视频| 法国伦理少妇愉情 | 波多野结衣一区二区三区高清 | 国产av一区二区三区传媒 | 一个人在线免费观看www | 国产精品亚洲lv粉色 | 亚洲综人网 | 久久激情小说 | 免费观看成年人视频 | 日日骚av一区二区 | 欧美一区二区三区免费看 | 日本a级c片免费看三区 | 国产粉嫩一区二区三区 | 婷婷丁香综合 | 国产又粗又黄 | 国产免费av电影 | 亚洲欧美激情视频 | 西方裸体在线观看 | 日韩专区在线播放 | 亚洲国产一区在线观看 | 瑟瑟综合网 | 麻豆传媒一区 | 你懂的视频在线播放 | 国产精品免费一区二区 | 国产91色 | 国产又粗又猛又爽 | a国产在线 | 黄网站在线免费 | 青草av在线| 久久精品视频无码 | 奇米影视四色777 | 三级黄色在线视频 | 狠狠综合久久 | 亚洲大片免费看 | 久久久999精品| 久久这里只有精品99 | 精品视频一区二区三区在线观看 | 欧美激情另类 | 黄色天堂av | 灌满闺乖女h高h调教尿h | 日韩福利网站 | 五月亚洲婷婷 | 涩涩视频在线免费看 | 中文天堂在线视频 | 狠狠爱综合 | 中文字幕av播放 | 久草热在线观看 | 麻豆av一区二区三区 | 国产日韩在线播放 | 久久只有这里有精品 | 丁香网五月天 | 性感美女一级片 | 羞羞影院体验区 | 国产老女人精品毛片久久 | 欧美高清视频在线观看 | 久久精品2019中文字幕 | 亚洲人成7777 | 最好看的mv中文字幕国语电影 | 婷婷视频一区二区三区 | 91国产视频在线 | 全肉的吸乳文 | 天天色综合色 | 拍国产真实乱人偷精品 |