freepeople性欧美熟妇, 色戒完整版无删减158分钟hd, 无码精品国产vα在线观看DVD, 丰满少妇伦精品无码专区在线观看,艾栗栗与纹身男宾馆3p50分钟,国产AV片在线观看,黑人与美女高潮,18岁女RAPPERDISSSUBS,国产手机在机看影片

正文內(nèi)容

程序員的自我修養(yǎng)總結(jié)(編輯修改稿)

2025-09-01 10:52 本頁面
 

【文章內(nèi)容簡介】 發(fā)生在連接的過程中,這個(gè)在前面已經(jīng)講過,重定位表記錄了重定位相關(guān)信息。 字符串表顧名思義,就是用來表示各種名稱的字符串的表。它是一個(gè)裝有各種字符串的表格,每個(gè)字符在表中都有一個(gè)固定的位置。這種表在ELF文件中保存為2種形式——.,它們分別是字符串表和段字符串表,它們在ELF文件中都以獨(dú)立的段而存在。為了輕松地找到這個(gè)段,在ELF文件頭中包含了這兩個(gè)段的下標(biāo),名為e_shstrndx。 鏈接的接口——符號(hào)鏈接是組合目標(biāo)文件的過程,目標(biāo)文件是根據(jù)彼此之間的地址相互引用,從而組合成可執(zhí)行文件的。而,這個(gè)地址可以簡單地理解為目標(biāo)文件中的函數(shù)和變量。在這里,函數(shù)和變量統(tǒng)稱為符號(hào),函數(shù)名和變量名統(tǒng)稱為符號(hào)名。鏈接器的著眼點(diǎn)主要在定義在本目標(biāo)文件和定義在其他目標(biāo)文件的全局性符號(hào),因?yàn)橹挥羞@些涉及到目標(biāo)文件之間的組合。 ELF符號(hào)表結(jié)構(gòu)ELF文件的符號(hào)表是一個(gè)段,段名為“.symtab”,它是一個(gè)Elf32_sym類型的數(shù)組,每個(gè)數(shù)組元素代表一個(gè)符號(hào)。在Elf32_sym結(jié)構(gòu)體中有一個(gè)32bit成員叫st_info,低4bit表示符號(hào)的類型,高28bit符號(hào)的綁定信息。綁定信息具體可見表315,符號(hào)類型可參見表316。:如果符號(hào)定義在本目標(biāo)文件中,它表示該符號(hào)所在的段在段表中的下標(biāo),否則它具有其他意義。st_shndx具體信息可見表317。:每個(gè)符號(hào)都有一個(gè)對應(yīng)值,它一般為變量和函數(shù)的地址。st_value的意義有如下幾種:如果符號(hào)定義在目標(biāo)文件中,并且它不是COMMON塊類型,則st_value代表符號(hào)在段中的偏移。如果符號(hào)定義在目標(biāo)文件中并且是COMMON塊類型,則st_value表示符號(hào)的對齊屬性。在可執(zhí)行文件中st_value表示符號(hào)的虛擬地址。 特殊符號(hào)鏈接器本身自帶的,不是你定義的,定義在鏈接腳本中的,但是你可以用的,這樣的符號(hào)是特殊符號(hào)。它們存在的時(shí)機(jī)是鏈接器鏈接生成可執(zhí)行文件時(shí),此時(shí)鏈接器會(huì)將它們解析成正確的值,書中P110舉了幾個(gè)具有代表性的特殊符號(hào)。 符號(hào)修飾與函數(shù)簽名本小節(jié)明確了函數(shù)簽名的概念。函數(shù)簽名:主要是指函數(shù)名和參數(shù)類型,其次是所在類和命名空間等。它用于區(qū)分不同函數(shù)。編譯器和連接器會(huì)使用名稱修飾的辦法加工函數(shù)簽名使之成為修飾后名稱,在C++中為符號(hào)名。不同的編譯器對函數(shù)簽名的修飾方法不同,這導(dǎo)致不同種類的目標(biāo)文件無法互連。原來C++編譯器已經(jīng)默認(rèn)定義了宏__cplusplus來兼容C語言和C++。 弱符號(hào)和強(qiáng)符號(hào)在不同目標(biāo)文件中含有相同全局性符號(hào)定義,這種情況被稱為強(qiáng)符號(hào),它會(huì)引起符號(hào)重定義。C/C++編譯器認(rèn)為未初始化的全局變量是弱符號(hào)。這個(gè)強(qiáng)弱符號(hào)是可以被定義的,所以強(qiáng)弱之別是根據(jù)定義來劃分的,并不針對符號(hào)的引用,P117代碼說明了這一點(diǎn)。鏈接器根據(jù)符號(hào)的強(qiáng)弱來處理和選擇定義的全局變量:不允許多次定義強(qiáng)符號(hào),否則報(bào)錯(cuò)。同一個(gè)符號(hào)在各目標(biāo)文件中出現(xiàn)了多次,但只有一個(gè)是強(qiáng)符號(hào),那么編譯器選擇強(qiáng)符號(hào)的那個(gè)。如果一個(gè)符號(hào)在所有目標(biāo)文件中都是弱符號(hào),那么編譯器選擇占用空間最大的一個(gè)。由此可見編譯器對于弱符號(hào)的選擇并不明顯,所以由弱符號(hào)造成的錯(cuò)誤也相對難以發(fā)現(xiàn)。強(qiáng)引用:目標(biāo)文件對于非本目標(biāo)文件的符號(hào)引用,在鏈接成可執(zhí)行文件的過程中,如果找不到該符號(hào)的定義,就報(bào)未定義錯(cuò)誤。弱引用:與強(qiáng)引用差不多,只不過在找不到符號(hào)時(shí)不報(bào)錯(cuò)。強(qiáng)弱引用主要用于庫的鏈接。對于未定義的弱引用,編譯器為便于識(shí)別把它看作是某一值,一般為0。弱符號(hào)與COMMON塊聯(lián)系較密切。弱引用是可以手動(dòng)聲明的,如P118第一段代碼所示。弱符號(hào)的作用在于提供一個(gè)默認(rèn)的庫符號(hào),但是當(dāng)用戶想要自定義該符號(hào)的時(shí)候,該自定義符號(hào)就獲得了更高的優(yōu)先級(jí)。而弱引用的作用在于增強(qiáng)了程序的可擴(kuò)展性,因?yàn)橛辛巳跻贸绦蚬δ芨鼜?qiáng),沒有弱引用程序也能正常運(yùn)行。 調(diào)試信息目標(biāo)文件和可執(zhí)行文件中都可能保存調(diào)試信息,ELF文件采用DWARF格式保存調(diào)試信息。由于調(diào)試信息與可執(zhí)行文件最終結(jié)果無關(guān),而且占用大量空間,所以在發(fā)布軟件時(shí)應(yīng)該去掉這些調(diào)試信息。第4章 靜態(tài)鏈接靜態(tài)鏈接是指將目標(biāo)文件鏈接在一起形成可執(zhí)行文件的過程。 空間與地址分配 相似段合并靜態(tài)鏈接過程是把各目標(biāo)文件中的各段合并到可執(zhí)行文件中的相應(yīng)段中。鏈接器為目標(biāo)文件分配地址和空間。這個(gè)空間有兩層含義,既包括在可執(zhí)行文件中占有的空間也包括在虛擬地址中分配的空間。其中虛擬地址空間的分配關(guān)系重大。靜態(tài)鏈接的過程一般分兩步——空間與地址分配。符號(hào)解析與重定位。第一步就是獲取段信息,合并段將它們映射到可執(zhí)行文件的段表信息中。整理符號(hào)和引用并放入全局符號(hào)表中。第二步,實(shí)際上就是鏈接,把目標(biāo)文件中的地址呀、符號(hào)呀、數(shù)據(jù)等進(jìn)行重定位然后鏈接。VMA:Virtual Memory AddressLMA:Load Memory Address鏈接前的VMA都是0,鏈接后就有實(shí)實(shí)在在的地址了。 符號(hào)地址的確定符號(hào)地址在原來的目標(biāo)文件中的每個(gè)段中都有一個(gè)偏移量,這個(gè)偏移量是固定的,所以在鏈接的過程中只要在虛擬地址的基礎(chǔ)上再加上這個(gè)偏移量就是某符號(hào)在虛擬地址空間中的地址。 符號(hào)解析與重定位在空間和地址分配完成以后,鏈接器即將進(jìn)行符號(hào)解析與重定位。本小節(jié)舉了個(gè)例子,用了很多匯編代碼,有些晦澀難懂。目標(biāo)文件中使用的都是虛擬地址不是物理地址,這一點(diǎn)很重要。目標(biāo)文件的起始地址都是0。 重定位表它存儲(chǔ)著與重定位相關(guān)的信息。每個(gè)要被重定位的ELF段都對應(yīng)一個(gè)重定位表,重定位表本身也是一個(gè)段,所以你也可以叫重定位表為重定位段。每一個(gè)要被重定位的地方叫做重定位入口。重定位入口的偏移表示入口在要被重定位的段中的位置。重定位表的實(shí)質(zhì)是一個(gè)Elf32_Rel的結(jié)構(gòu)體數(shù)組,每個(gè)數(shù)組元素對應(yīng)一個(gè)重定位入口。 符號(hào)解析重定位的過程伴隨著符號(hào)解析的過程。每個(gè)重定位的入口對應(yīng)一個(gè)符號(hào)引用,鏈接器會(huì)查找有所有目標(biāo)文件的符號(hào)表所組成的全局符號(hào)表,然后根據(jù)這個(gè)全局符號(hào)表進(jìn)行重定位。 指令修正方式32位x86平臺(tái)下的ELF文件的重定位入口所修正的指令尋址方式只有2種:絕對近址32位尋址和相對近址32位尋址。修正的位置長度為4bytes。經(jīng)過絕對地址修正方式修正得到的地址是該符號(hào)的實(shí)際地址,而相對地址尋址方式得到的是符號(hào)與被修正位置的距離。 COMMON塊相同的符號(hào)定義在多個(gè)不同的目標(biāo)文件中,但是類型各不相同,這說明它們不是同一個(gè)變量或者函數(shù),因此不能對它們進(jìn)行相同的操作。但是鏈接器只認(rèn)符號(hào)不認(rèn)類型,它認(rèn)為它們都一樣。這種情況主要分為3種:至少2個(gè)強(qiáng)符號(hào)類型不一致。一個(gè)強(qiáng)符號(hào)和多個(gè)弱符號(hào)類型不一致。至少2個(gè)弱符號(hào)類型不一致。強(qiáng)符號(hào)是指定義在目標(biāo)文件中全局性符號(hào),包括函數(shù)和變量,顯然它們?nèi)绻邢嗤亩鄠€(gè),那就是重定義,這本身就會(huì)報(bào)錯(cuò)?,F(xiàn)在的編譯器和鏈接器都支持COMMON塊機(jī)制。它主要針對的對象是弱符號(hào)。如果在眾多符號(hào)之中有一個(gè)符號(hào)是強(qiáng)符號(hào),那么符號(hào)所占空間與強(qiáng)符號(hào)相同。如果弱符號(hào)大小超過強(qiáng)符號(hào),編譯器會(huì)發(fā)出警告。編譯器為什么不把未初始化的全局變量當(dāng)做未初始化的局部靜態(tài)變量處理?為什么不在bss中給它們分配空間,而非要把它們標(biāo)記為COMMON類型呢?因?yàn)榫幾g時(shí)編譯器不知道弱符號(hào)需要多大空間,所以這時(shí)無法為其在BSS中分配空間,只能當(dāng)做局部靜態(tài)變量處理。但是在鏈接的時(shí)候可以確定,所以鏈接以后才在BSS中分配空間。編譯器把所有未初始化的全局變量都當(dāng)成COMMON類型處理,這樣做是為了與強(qiáng)類型分開,凡是非COMMON類型的都是強(qiáng)類型。多個(gè)強(qiáng)類型的符號(hào)會(huì)發(fā)生重復(fù)定義的錯(cuò)誤。 重復(fù)代碼消除C++在很多時(shí)候會(huì)產(chǎn)生重復(fù)代碼,模版是其中最具代表性的一個(gè)。模版可以在不同的編譯單元被實(shí)例化成相同的類型,兩個(gè)完全一樣的類是完全沒有必要的,一個(gè)足矣。不解決代碼重復(fù)問題會(huì)導(dǎo)致:空間浪費(fèi)。這個(gè)根本就不用解釋。地址容易出錯(cuò)。因?yàn)槭嵌鄠€(gè)相同的實(shí)例嘛,就會(huì)有多個(gè)指針分別指向這些實(shí)例,但是這些實(shí)例之間沒差別,它們在邏輯上是同一函數(shù),這就容易造成指針的誤指。指令運(yùn)行效率較低。緩存機(jī)制會(huì)緩存多份重復(fù)的代碼,但是程序只會(huì)用特定的一份,在這么多份相同的代碼中找特定的一份不好找,成功率較低,即,緩存命中率低。解決方案:把每個(gè)編譯單元中的每個(gè)模版的不同實(shí)例分別放進(jìn)不同的段中,并且對不同的單元都這樣做,這樣在最后鏈接的時(shí)候不同編譯單元中的相同實(shí)例段就合并從而消除多份相同的實(shí)例。缺點(diǎn):不同的編譯單元可能使用了不同的編譯器版本或者優(yōu)化選項(xiàng),這會(huì)導(dǎo)致實(shí)際產(chǎn)生的代碼不同,鏈接器必須選擇其中一個(gè)副本。函數(shù)級(jí)別鏈接:默認(rèn)情況下鏈接器會(huì)把所有的目標(biāo)文件鏈接在一起,不管有用的代碼還是沒用的代碼,這會(huì)導(dǎo)致可執(zhí)行文件很大。所謂函數(shù)級(jí)別鏈接就是每個(gè)編譯單元也把函數(shù)單獨(dú)放進(jìn)一個(gè)段中,在鏈接的時(shí)候只鏈接那些有用的函數(shù)段。這種做法會(huì)減慢編譯和鏈接的過程,因?yàn)槎蔚臄?shù)量增加了。 全局構(gòu)造與析構(gòu)在C++中全局對象的構(gòu)造在main之前完成,析構(gòu)在main之后完成。init段包含了進(jìn)程的初始化代碼,在main之前執(zhí)行。fini段包含了進(jìn)程的終止代碼,在main之后執(zhí)行。C++的全局構(gòu)造和析構(gòu)由此實(shí)現(xiàn)。 C++與ABI把不同編譯器產(chǎn)生的目標(biāo)文件鏈接在一起需要特定的條件——相同的ABI(Application Binary Interface)。ABI:符號(hào)修飾標(biāo)準(zhǔn)、變量內(nèi)存布局、函數(shù)調(diào)用方式等與二進(jìn)制兼容性相關(guān)的內(nèi)容。C語言間的目標(biāo)文件能否互相兼容具體決定于如下幾個(gè)方面:內(nèi)置類型大小和存儲(chǔ)方式。組合類型大小和存儲(chǔ)方式。外部符號(hào)與用戶定義的符號(hào)之間的命名方式和解析方式。函數(shù)調(diào)用方式。堆棧分布方式。寄存器使用方式。C++在這方面的決定因素P141+P142介紹。C++代碼不僅對于由不同編譯器編譯得到的目標(biāo)文件不兼容,而且就算是同一編譯器的不同版本編譯得到的目標(biāo)文件也不兼容。這都是ABI鬧的。 靜態(tài)庫鏈接開發(fā)環(huán)境往往附帶語言庫,這些庫是對系統(tǒng)API的封裝。大部分的C語言庫函數(shù)都調(diào)用了系統(tǒng)API,少數(shù)除外。靜態(tài)庫實(shí)際上可以看成是一組目標(biāo)文件的集合。C語言中看似簡單的庫函數(shù)和系統(tǒng)中眾多的API存在著依賴關(guān)系。靜態(tài)鏈接的過程分為三步:調(diào)用C語言編譯器。把C語言程序變成匯編語言程序。調(diào)用匯編器。把匯編程序變成目標(biāo)文件。調(diào)用鏈接器鏈接成可執(zhí)行文件。 鏈接過程控制WINDOWS內(nèi)核其實(shí)就是一個(gè)文件——\WINDOWS\system32\。雖然大多數(shù)情況下,鏈接器是對目標(biāo)文件進(jìn)行鏈接,但是對某些系統(tǒng)軟件來說卻不是這樣的。 鏈接過程腳本有幾種控制鏈接過程的方法:使用命令行來指定參數(shù)。這就像WINDOWS下的CMD和LINUX下的SHELL。編譯器通過把鏈接指令存儲(chǔ)進(jìn)目標(biāo)文件中實(shí)現(xiàn)自動(dòng)鏈接。用鏈接腳本來控制連接過程。 最“小”的程序C語言程序的執(zhí)行入口其實(shí)不是main而是庫中的_start。編譯器會(huì)把只打印字符串的printf優(yōu)化為puts。 使用ld鏈接腳本鏈接控制腳本是用一種特別的語言寫成包含為數(shù)不多操作。輸入文件中的段是輸入段,輸出文件中的段是輸出段,鏈接控制的過程就是從輸入段到輸出端的過程。 ld鏈接腳本語法簡介它由命令語句和賦值語句組成??傮w來講它類似于C語言。本節(jié)就是大概地介紹了一下鏈接腳本語法規(guī)則而已。 BFD庫BFD(Binary File Descriptor Library)為不同目標(biāo)文件格式提供統(tǒng)一接口,達(dá)到跨平臺(tái)。你需要做的只是操作抽象的目標(biāo)文件?,F(xiàn)在編譯器通常不直接處理目標(biāo)文件,而是通過BFD。第5章 WINDOWS PE/COFF Windows的二進(jìn)制文件格式PE/COFFWin32平臺(tái)下標(biāo)準(zhǔn)文件格式為PE,PE=Protable Executable。PE和ELF同根同源都是從COFF(Common Object File Format)發(fā)展而來。 PE的前身COFFPE文件被裝載時(shí)直接映射到進(jìn)程虛擬空間中運(yùn)行,它是進(jìn)程虛擬空間的映像,所以PE很多時(shí)候被稱為映像文件。 鏈接指示信息COFF文件結(jié)構(gòu)和ELF文件結(jié)構(gòu)大體相同,只是前者多了兩個(gè)段——drectve段和debug$S段。drectve很顯然就是directive的某種縮寫形式,而directive是指令的意思,因此它是編譯器傳遞給鏈接器的鏈接指令。 調(diào)試信息在COFF中所有以debug開頭的段都是調(diào)試信息段。debug$S表示與符號(hào)相關(guān)的調(diào)試信息段。還有其他段可參見P165。 大家都有符號(hào)表與ELF不同的是COFF還會(huì)為字符串常量自動(dòng)生成符號(hào)。 WINDOWS下的ELF——PEPE比COFF多了兩個(gè)主要的變化:PE文件的開始部分是DOS MZ可執(zhí)行文件格式的文件頭和樁代碼。COFF格式中的IMAGE_FILE_HEADER被擴(kuò)展成為IMAGE_NT_HEADERS。DOS和WINDOWS下的可執(zhí)行文件格式都是exe,但是DOS下的卻是MZ格式。第6章 可執(zhí)行文件的裝載與進(jìn)程MMU(Memory Management Unit):內(nèi)存管理單元,它將虛擬地址轉(zhuǎn)換位物理地址。 進(jìn)程的虛擬地址空間程序和進(jìn)程的區(qū)別:程序是靜態(tài)的,進(jìn)程是動(dòng)態(tài)的。進(jìn)程是程序運(yùn)行時(shí)的一個(gè)過程,程序是預(yù)先編譯好的指令和數(shù)據(jù)的集合。一般來說C語言中的指針大小與虛擬地址空間的位數(shù)相同,例如,Win32平臺(tái)下虛擬地址空間為32位,所以指針大小也是32位。程序都是運(yùn)行在虛擬地址空間中的。一般來講,內(nèi)存空間被分成兩部分——系統(tǒng)區(qū)和用戶區(qū),我們平時(shí)所能操作的都是用戶區(qū),系統(tǒng)區(qū)是被禁止的。32位的CPU最大支持4G內(nèi)存,這實(shí)際上說的是虛擬地址空間大小,但實(shí)際上你可以將物理地址空間擴(kuò)展到4G以上。所謂的32位的操作系統(tǒng)也就是支持最大虛
點(diǎn)擊復(fù)制文檔內(nèi)容
環(huán)評公示相關(guān)推薦
文庫吧 www.dybbs8.com
備案圖片鄂ICP備17016276號(hào)-1