第六章源代碼編譯和調(diào)試連接概覽_第1頁(yè)
第六章源代碼編譯和調(diào)試連接概覽_第2頁(yè)
第六章源代碼編譯和調(diào)試連接概覽_第3頁(yè)
第六章源代碼編譯和調(diào)試連接概覽_第4頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、編譯連接四過(guò)程連接1、編譯連接過(guò)程概覽連接的目預(yù)處理或的目預(yù)處理或預(yù)編譯匯編編譯匯編編譯符號(hào)解析 a、符號(hào)確定和調(diào)整 b、如果使用靜態(tài)庫(kù)話,需 要拷貝靜態(tài)庫(kù)重定位,給定鏈接符號(hào)解析 a、符號(hào)確定和調(diào)整 b、如果使用靜態(tài)庫(kù)話,需 要拷貝靜態(tài)庫(kù)重定位,給定鏈接地址目的:生成ELF格式可執(zhí)行文件命令:gcc -o a a.c/a.i/a.s的目的目的目的目將a.s,生成為將a.s,生成為ELF格式的可重定位目標(biāo)文件a.o,命令:gcc -c a.c -o a.o對(duì)#內(nèi)容做處理,生成a.i的擴(kuò)展性c文件命令:gcc -E a.c -o a.i cpp a.c -o a.i生成機(jī)器匯編a.s,機(jī)器匯編包

2、含了a.o需要的各種符號(hào)命令:gcc -S a.c -o a.s以上的4個(gè)步驟中的鏈接,是相對(duì)比較難理解。但是充分地理解鏈接,對(duì)于我們來(lái)說(shuō)還是很有幫助的。有助于構(gòu)造大型程序,因?yàn)闃?gòu)造大型程序往往需要很多模塊和庫(kù)的支持,但是在鏈接這些模塊和庫(kù)時(shí),所提示的錯(cuò)誤也往往讓人很迷惑,但是如果你很好的理解了編譯鏈接的過(guò)程的話,這將不是難題。有助于對(duì)函數(shù)和全局變量的鏈接域概念,進(jìn)行深入地理解。有助于理解與系統(tǒng)相關(guān)的知識(shí):如何加載可執(zhí)行文件運(yùn)行,什么是虛擬內(nèi)存,什么分頁(yè)和內(nèi)存映射等。理解有關(guān)庫(kù)(動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù))的概念。2、各個(gè)步驟詳細(xì)描述2.1第1步,預(yù)編譯所需工具軟件:預(yù)處理器目的:處理所有#開頭的指令,生

3、成xxx.i的擴(kuò)展性c源文件處理內(nèi)容:a)、宏展開,將宏用實(shí)際的宏常量替換b)、頭文件包含(頭文件可嵌套包含),將頭文件中所有的類型定義和函數(shù)聲明包含到c文件c)、處理?xiàng)l件編譯,將條件編譯允許的代碼留在c文件中,不允許的排除在外a.c#include #include#include #include #define STR hellostatic int c = 100;char b = 1;char *p = STR;int h; struct kk int e; char f; ;struct kk yy = 100, a;int main(int kk, char *argv)/arg

4、v存放參數(shù)的 int i = 0; int a = 0; a = +i + +i + +i; printf(a = %d, i = %dn, a, i); return 0;加了這么多的全局變量,僅僅是為了加了這么多的全局變量,僅僅是為了全面的說(shuō)明匯編文件的結(jié)構(gòu)而已ls -al a.c 查看文件大小-rw-rw-r-. 1 linux linux 388 Mar 11 16:12 a.c /紅色字體是文件的大小file a.c /查看文件的類型c: UTF-8 Unicode C program text /c程序文本文件,UTF-8 Unicode含中文編碼的格式,目的主要/是為了能夠?qū)代

5、碼做各種的中文注釋命令:gcc -E a.c -o a.i 或者 cc1 a.c -o a.i ,cc1是處理軟件,a.c是被輸入數(shù)據(jù),a.i是加工后數(shù)據(jù)生成的a.i文件如下:。1841 static int c = 100;。1841 static int c = 100;1842 char b = 1;/STR宏展開,被”hello”替換1843 char *p = hello;1844 int h;1845 struct kk1846 1847 int e;1848 char f;1849 ;1850 struct kk yy = 100, a;1851 1852 int main(in

6、t kk, char *argv)1853 1854 int i = 0;1855 int a = 0;1856 a = +i + +i + +i;1857 printf(a = %d, i = %dn, a, i);1858 return 0;1859 包含了各種的函數(shù)聲明和類型定義。 486 extern int fprintf (FILE *_restrict _stream, 487 _const char *_restrict _format, .);。/我們需要調(diào)用到的函數(shù)extern int printf (_const char *_restrict _format, .);。

7、 extern int vprintf (_const char *_restrict _format, _gnuc_va_list _arg ); 508 509 extern int vsprintf (char *_restrict _s, _const char *_restrict _forma t, 510 _gnuc_va_list _arg) _attribute_ (_nothrow_);。 919 typedef struct 920 921 int quot; 922 int rem; 923 div_t; 924 925 ls -al a.i 查看文件大小-rw-rw-

8、r-. 1 linux linux 39324 Mar 11 16:16 a.i /紅色字體是文件的大小file a.i /查看文件的類型a.i: ASCII C program text /c程序文本文件,純英文編碼格式a.c 變?yōu)閍.i后,變化如下:a)、文件大小從388變?yōu)榱?9324,因?yàn)閷?dǎo)入了頭文件b)、文件格式從UTF-8 Unicode變?yōu)榱薃SCII,也就是說(shuō)從包含中文的編碼格式,變?yōu)榱思冇⑽牡木幋a格式,但是如果printf(“你好n”);中,或其他的字符串中包含了中文的話,格式還會(huì)保持為UTF-8 Unicode格式,所以a.i到底是UTF-8 Unicode還是ASCII格

9、式,就看字符串中包不包含中文。2.2、第2步,編譯所需軟件工具:編譯器(c語(yǔ)言的詞法語(yǔ)法分析)目的:生成對(duì)硬件針對(duì)性很強(qiáng)的機(jī)器匯編文件, gcc生成x86的機(jī)器匯編指令,arm-linux-gcc生成arm 的機(jī)器匯編指令處理內(nèi)容:詞法語(yǔ)法分析,將跨平臺(tái)的高級(jí)語(yǔ)言c語(yǔ)言編譯為x86的機(jī)器匯編命令:gcc -S a.i(a.c) -o a.s 編譯器是處理軟件,a.i是被輸入數(shù)據(jù),a.s是加工后數(shù)據(jù)a.s .file a.c /文件名 .file a.c /文件名/* 到.size c, 4前都是對(duì)變量c的說(shuō)明,沒(méi)有g(shù)lobale修飾代表是本地變量,只有本.c文件才能訪問(wèn)到*/ .data /初

10、始化的數(shù)據(jù)節(jié) .align 4 /4字節(jié)對(duì)齊存放 .type c, object /類型是變來(lái)那個(gè) .size c, 4 /占4個(gè)字節(jié)的空間 c: /c標(biāo)號(hào) .long 100 /.long等價(jià)于.int或.word,100存放于一個(gè)字的空間 .globl b /globle代表其它的.c文件也能夠訪問(wèn)到,說(shuō)明了它的鏈接域 .type b, object /變量 .size b, 1 /占1字節(jié) b: .byte 49 /1的ascii值 .globl p .section .rodata /常量數(shù)據(jù)節(jié) .LC0: /標(biāo)號(hào) .string hello .data /指針p放在數(shù)據(jù)段,p中方“h

11、ello” /的在常量節(jié)的存放地址 .type p, object /p是變量(指針變量) .size p, 4 /4個(gè)字節(jié),地址都是4個(gè)字節(jié) p: .long .LC0 /將“hello”在常量節(jié)的存放首地址,賦給指針變量p .comm h,4,4 /是未初始化的全局變量,它是一個(gè)弱符號(hào),鏈接時(shí)可能會(huì)與其它同名符號(hào)合并, /如果長(zhǎng)度不一致,選擇長(zhǎng)度大那個(gè),如果遇到了強(qiáng)符號(hào),就選擇強(qiáng)符號(hào),/其實(shí)這里涉及到了聲明和定義的問(wèn)題,.comm代表h是可能會(huì)被合并的通用符號(hào)/這個(gè)對(duì)于鏈接時(shí)的符號(hào)解析是非常有用的,第一個(gè)4代表空間大小。第二個(gè)4代表/對(duì)齊方式(4字節(jié)對(duì)齊),他必須是2的冪次,它是未被初始化

12、的若符號(hào),最后被合并后的還/是個(gè)若符號(hào)的話,它就會(huì)被存在.bss段(在沒(méi)有運(yùn)行前,.bss里只有占位符,沒(méi)有空間) .globl yy /yy是結(jié)構(gòu)體 .align 4 /4字節(jié)對(duì)齊存放 .type yy, object /變量 .size yy, 8 /共8字節(jié)(為適當(dāng)對(duì)齊) yy: .long 100 /結(jié)構(gòu)體第一個(gè)變量的值 .byte 97 /結(jié)構(gòu)體第二個(gè)變量的值,.byte代表只有一個(gè)字節(jié) .zero 3 /空字節(jié)有3個(gè),因?yàn)榻Y(jié)構(gòu)適當(dāng)對(duì)齊(適當(dāng)對(duì)齊將c語(yǔ)言時(shí)講解),只用了5個(gè)字節(jié),利用/3字節(jié)空的空間占位用 .section .rodata /后面的格式化輸出的,字符串當(dāng)?shù)莱A抗?jié).LC

13、1: .string a = %d, i = %dn /printf的格式字符串機(jī)器匯編余下部分代碼如下:機(jī)器匯編余下部分代碼如下: .text/代表后面的main放在大媽段 .globl main /表明main是全局的符號(hào) .type main, function /符號(hào)main是函數(shù) main: /標(biāo)號(hào),給人看的,對(duì)機(jī)器來(lái)說(shuō)無(wú)意義/*紅色字體前的4句話是涉及到實(shí)參,調(diào)用函數(shù)返回地址,調(diào)用函數(shù)棧幀,局部變量新棧幀和棧頂?shù)娜霔:妥兓灰桌斫?,這里就不描述*/ pushl %ebp movl %esp, %ebp andl $-16, %esp subl $32, %esp/*一下紅色部分對(duì)

14、應(yīng)a.c的紅色部分,我會(huì)寫* 是a = +i + +i + +i;的匯編實(shí)現(xiàn) */ movl $0, 24(%esp) /24(%esp) 代表內(nèi)存位置,24代表%esp存放地址+24 movl $0, 28(%esp) addl $1, 24(%esp) addl $1, 24(%esp) movl 24(%esp), %eax addl %eax, %eax addl $1, 24(%esp) addl 24(%esp), %eax movl %eax, 28(%esp) /*下面是printf()實(shí)現(xiàn),需要給a格式字符串,給它a和i的值,新開兩個(gè)空間來(lái)存放,為什么新開 *兩個(gè)空間來(lái)訪a和

15、i,自己思考*/ movl $.LC1, %eax /.LC1:printf格式字符串首地址 movl 24(%esp), %edx movl %edx, 8(%esp) movl 28(%esp), %edx movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave /函數(shù)棧釋放等事宜。ls -al a.s 查看文件大小-rw-rw-r-. 1 linux linux 971 Mar 11 18:25 a.s /紅色字體是文件的大小file a.s /查看文件的類型a.s: ASCII assembler pro

16、gram text /純英文編碼的匯編文本文件a.s 變?yōu)閍.i后,變化如下:a)、文件大小相對(duì)于a.i的39324,a.s變小為了971,因?yàn)?c文件中只用到了printf一個(gè)動(dòng)態(tài)庫(kù)函數(shù)函數(shù),而預(yù)處理卻將所有的標(biāo)準(zhǔn)io動(dòng)態(tài)庫(kù)函數(shù)的聲明和類型定義全部放到了.i中,但是編譯時(shí),只需要用到printf一個(gè)函數(shù)符號(hào)即可,所以會(huì)小了非常多,但是記住printf庫(kù)函數(shù)并沒(méi)有被復(fù)制進(jìn)入a.s中,函數(shù)聲明也只是告訴編譯器,如果找不到printf函數(shù)符號(hào),不要報(bào)警告和錯(cuò)誤了,這不是一個(gè)問(wèn)題,該函數(shù)在其它地方有實(shí)現(xiàn),鏈接時(shí)連接進(jìn)來(lái)即可,那么其它地方,有可能是其它.c,也有可能是其它庫(kù)函數(shù),這里printf就是庫(kù)

17、函數(shù)。但是相對(duì).c文件388,a.s的971還是大了很多,原因是一條c代碼會(huì)被翻譯成很多條匯編指令,因此文件會(huì)大很多,也不足為奇。b)、我們知道a.i的文件格式是UTF-8 Unicode還是ASCII格式,就看使用到的字符串中有沒(méi)有包含中文,如printf(“你好”);這個(gè)字符串就是中文,但是不管a.i是什么格式,生成的a.s 都是ASCII格式,因?yàn)榧幢愫兄形?,中文也?huì)變?yōu)閍scii的數(shù)字編碼,如“你好”就會(huì)變?yōu)?344275240345245275,這些數(shù)字均是ascii碼。備注:機(jī)器匯編中main函數(shù)前面的各種帶點(diǎn)(.)的符號(hào)很重要,后面可重定位目標(biāo)文件的符號(hào) 表的生成需要用到他們2

18、.3、第3步,匯編所需軟件工具:匯編器目的:將x86機(jī)器匯編指令,匯編成為ELF格式的二進(jìn)制可重定位目標(biāo)文件處理內(nèi)容:匯編的詞法語(yǔ)法分析命令:gcc -c a.s(a.c) -o a.o 或 as a.s -o a.o ,as是匯編處理程序,a.s是輸入數(shù)據(jù),a.o是加工后數(shù)據(jù)a.o?ELFAAAACADA 4(L U D$XD$D$XA D$XAD$XAD$XACD$XD$FT$XT$HT$ T$DD$d1dahel lo a = %d, i = %d 2 GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3).symtab.strtab.shstrt men

19、t.note.GNU-stack _ AF4ZD 0DP 3 ADH)ACT D% DH 我們打開a.o發(fā)現(xiàn),居然是亂碼,其實(shí)我們認(rèn)為是亂碼,但是不是的,文本編輯器忠實(shí)地按照要求翻譯了這些二進(jìn)制代碼的,只是不是人所能夠識(shí)別的格式而已,但是紅色字體的ELF格式頭我們能看的很清楚,說(shuō)明該文件是ELF格式的。ls -al a.o 查看文件大小-rw-rw-r-. 1 linux linux 1096 Mar 11 18:58 a.o /紅色字體是文件的大小file a.o /查看文件的類型/ELF格式 32 linux standard base 可重定位文件,用于x86平臺(tái),版本1,未瘦身(包含各

20、類符號(hào)表)a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not strippeda.o 變?yōu)閍.s后,變化如下:a)、a.o的 1096和a.s的971基本差不多,只是a.o中多了些符號(hào)表,文件稍大些b)、a.s的ASSCII格式轉(zhuǎn)為了a.o的ELF二進(jìn)制格式將a.o進(jìn)行反匯編:我們知道a.o是二進(jìn)制文件,不是我們?nèi)四軌蚩炊母袷剑敲次覀兙托枰环N方法來(lái)看懂,那就是反匯編反匯編命令:objdump -D a.o u_a.su_a.s 2 a.o: file format elf32-i386 2 a.o: fi

21、le format elf32-i386。 5 Disassembly of section .text: 6 7 00000000 : 8 0: 55 push %ebp 9 1: 89 e5 mov %esp,%ebp。 34 Disassembly of section .data: 35 36 00000000 : 37 0: 64 00 00 add %al,%fs:(%eax) 。 53 Disassembly of section .rodata: 54 55 00000000 : 56 0: 68 65 6c 6c 6f push $0 x6f6c6c65 57 5: 00 2

22、0 add %ah,(%eax)。 65 Disassembly of section .comment: 66 67 00000000 : 68 0: 00 47 43 add %al,0 x43(%edi) 69 3: 43 inc %ebx 70 4: 3a 20 cmp (%eax),%ah。對(duì)于從a.o反匯編來(lái)的u_a.s反匯編文件,我們并不需要知道里面的指令的含義,我們需要關(guān)心的是文件的組成結(jié)構(gòu),黑體代表組成的各個(gè)節(jié),紅色為機(jī)器匯編指令,粉紅為匯編對(duì)應(yīng)的二進(jìn)制機(jī)器碼,藍(lán)色代表的是各個(gè)指令在各自節(jié)中的定位地址由上我們知道如下幾件事、a.o的定位地址從0開始、代碼被劃分回了這么幾個(gè)段、

23、代碼段:只有.text也稱為代碼節(jié)、數(shù)據(jù)段:.data:靜態(tài)數(shù)據(jù)節(jié),.rodata:常量數(shù)據(jù)節(jié),.comment:若符號(hào)節(jié)關(guān)于*.o的可重定位目標(biāo)文件文件,ELF(Executable and Linkable Format, ELF)格式說(shuō)明目標(biāo)文件種類、如.o的可重定位目標(biāo)文件(包括.a):包含二進(jìn)制的代碼和數(shù)據(jù),鏈接時(shí)可以和其它的可重定位 目標(biāo)文件一起合并起來(lái),形成一個(gè)可執(zhí)行二進(jìn)制文件、可執(zhí)行目標(biāo)文件:包含二進(jìn)制的數(shù)據(jù)和指令,可直接被加載器加載到虛擬內(nèi)存上運(yùn)行、共享庫(kù)目標(biāo)文件:其實(shí)就是動(dòng)態(tài)庫(kù)文件,一種特殊的可重定位文件,可以在程序運(yùn)行時(shí),動(dòng)態(tài) 的被加載到內(nèi)存中運(yùn)行,以便提供功能支持.o文

24、件的ELF格式文件.o為什么需要ELF格式,因?yàn)槲覀兊某绦虻倪\(yùn)行,是需要依賴于這個(gè)格式的,因此我們?cè)谏蒩.o時(shí)就需要將其a.s中的符號(hào)數(shù)據(jù)以ELF重新組合生成a.o文件,為最終生成ELF格式的可執(zhí)行文件a做好準(zhǔn)備。那么ELF格式是什么格式呢?實(shí)際上.o文件的ELF格式與可執(zhí)行文件的ELF格式略有些不同的,以下是.o文件的ELF格式說(shuō)明段索引號(hào)段名11節(jié)頭部表10.strtab9.line8.debug7.rel.data6.rel.text5.symtab4.bss3 .data2.rodata1.textELF頭.o里面其實(shí)是.comm.o里面其實(shí)是.comm各節(jié)說(shuō)明:ELF頭:計(jì)算機(jī)字大

25、?。ㄎ覀兊氖?字節(jié)),大小端序,和幫助連接器語(yǔ)法分析和解釋目標(biāo)文件 的信息.text: 代碼節(jié)(已編譯程序的機(jī)器指令代碼存放處).rodata:常量數(shù)據(jù)節(jié),比如char *p = “hello”;指針字符串,“hello”就是放在這里,但p不放在這 里,p具體放在那里根據(jù)是局部變量還是全局變量而定,printf(“a = %dn”, a);中的“a = %dn”,字符串也放在這里。.data: 初始化的靜態(tài)變量放在這里,如全局的int a = 100;局部的靜態(tài)局部變量static int b = 10; 也放在這里,如果沒(méi)有static修飾的局部變量,在運(yùn)行是放到棧里,這里是a.o文件, 這

26、里沒(méi)有可執(zhí)行文件,還談不上運(yùn)行,所以還沒(méi)有棧。.bss(Block Storage Start):未初始化的靜態(tài)變量,不過(guò)運(yùn)行時(shí),會(huì)幫忙全部清零,.o里面這 個(gè)段只有占位符,實(shí)際不占磁盤空間,我們?yōu)榱撕糜浻洖閎etter save space,.o文件里 的.bss準(zhǔn)確來(lái)說(shuō)應(yīng)該是,comm,所有.o的.comm合并(同名符號(hào)統(tǒng)一后)后才是.bss.symtab:程序中定義和引用的(調(diào)用)函數(shù)和全局變量的信息(符號(hào)解析需要用到),注意沒(méi)有 局部變量。我定義了全局變量int a = 100;這個(gè)符號(hào)a就包含很多信息,如符號(hào)類 型(變量),空間大小,鏈接類型等等,其實(shí)這些信息在機(jī)器匯編.s文件中也有

27、體現(xiàn), 但是生成.o后,所有的符號(hào)信息集中放在這里。1、符號(hào)類型模塊m中定義的全局符號(hào),如不帶static修飾的鏈接域是全局的函數(shù)和全局變量其它模塊定義,但是有本m模塊引用的全局符號(hào),稱為外部符號(hào),如其它模塊中如不帶static修飾的鏈接域是全局的函數(shù)和全局變量只被本m模塊使用的本地符號(hào),如帶static的全局變量和函數(shù),自動(dòng)局部變量符號(hào)在棧中管理,但是帶static的局部變量卻歸類為本地符號(hào),根據(jù)有無(wú)初始化分別在.data和.bss中管理,如果出現(xiàn)重名,重名的符號(hào)在解析時(shí)將會(huì)被唯一化。.data /數(shù)據(jù)段 .align 4 /4字節(jié)對(duì)齊存放.data /數(shù)據(jù)段 .align 4 /4字節(jié)對(duì)齊

28、存放 .type c, object /類型是變量 .size c, 4 /占4個(gè)字節(jié)的空間 c: .long 100 /變量值我們從上面了解到c的這幾個(gè)信息:(1) 4字節(jié)對(duì)齊存放 (2)符號(hào)類型是變量(object表示) (3)占4字節(jié)空間 (4)變量值為100 (5)連接類型是局部的(沒(méi)有g(shù)loble修飾)生成a.o后,這些信息會(huì)收集到.symtab這個(gè)段中,我們運(yùn)行readelf -s a.o打印出a.o的符號(hào)列表看看,有關(guān)c的描述是否正確? Num: Value Size Type Bind Vis Ndx Name Num: Value Size Type Bind Vis Ndx

29、 Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FILE LOCAL DEFAULT ABS a.c/ABS不可重定位符號(hào) 2: 00000000 0 SECTION LOCAL DEFAULT 1 3: 00000000 0 SECTION LOCAL DEFAULT 3 4: 00000000 0 SECTION LOCAL DEFAULT 5 5: 00000000 0 SECTION LOCAL DEFAULT 6 6: 00000000 0 SECTION LOCAL DEFAULT 8 7: 00000000 0

30、 SECTION LOCAL DEFAULT 7 8: 00000000 4 OBJECT LOCAL DEFAULT 3 c 9: 00000004 1 OBJECT GLOBAL DEFAULT 3 b 10: 00000008 4 OBJECT GLOBAL DEFAULT 3 p 11: 00000004 4 OBJECT GLOBAL DEFAULT COM h /COM通用符號(hào),對(duì)應(yīng).s的.comm 12: 0000000c 8 OBJECT GLOBAL DEFAULT 3 yy 13: 00000000 90 FUNC GLOBAL DEFAULT 1 main 14: 000

31、00000 0 NOTYPE GLOBAL DEFAULT UND printf /UND未定義符號(hào)Num:符號(hào)編號(hào) Value:符號(hào)所致內(nèi)容在所在節(jié)中的偏移 Size:內(nèi)容占空間大小 Type:符號(hào)類型,如文件,變量,函數(shù)無(wú)類型等等 Bind:鏈接域:涉及c中static標(biāo)志 Ndx:所在節(jié)編號(hào) Name:符號(hào)名稱上面的紅色信息就是對(duì)變量c符號(hào)的描述。信息基本符合,唯獨(dú)值(value)不符合,因?yàn)樗膶?shí)際值放在的3指向的節(jié).data段里面,這里根本不用存入。這個(gè)無(wú)需-g選項(xiàng)就能得到.rel.text:所有的.o合成一個(gè)可執(zhí)行文件時(shí),所有的.o同名節(jié)會(huì)合并在一起,那么重定位時(shí)就會(huì)有 很多需要修

32、改的地方,這個(gè)節(jié)里面就記錄了在合并時(shí).text中需要修改的位置.rel.data:記錄了.data在合并時(shí)需要修改的位置,任何全局變量的信息在重定位時(shí)需要被修改.bebug: 調(diào)試符號(hào)表,其條目是程序中定義的局部變量和它的類型定義,以及程序中定義和引用 的局部變量,-g選項(xiàng)才能得到,對(duì)于GDB調(diào)試來(lái)說(shuō)很重要.line: 原始c程序中每行c代碼的行號(hào)和現(xiàn)在生成的機(jī)器代碼間的對(duì)應(yīng)關(guān)系,這個(gè)關(guān)系對(duì)于調(diào) 試來(lái)說(shuō)也是很重要的,沒(méi)有行號(hào),很難進(jìn)行錯(cuò)誤定位,-g選項(xiàng)得到.strtab:一個(gè)字符串表,包含了各個(gè)節(jié)的名字,這些名字字符串以null結(jié)尾備注:1、前面的紅色部分重點(diǎn)掌握,最兩個(gè).debug和.lin

33、e節(jié)可以用strip命令進(jìn)行瘦身。 2、a.o的ELF格式非常重要,它為后面連接生成ELF格式的可執(zhí)行文件打下基礎(chǔ)2.4、第4步,鏈接所需軟件工具:連接器目的:將x86ELF格式的各個(gè).o文件鏈接為二進(jìn)制ELF格式的可執(zhí)行目標(biāo)文件處理內(nèi)容:根據(jù)鏈接腳本的要求,鏈接各個(gè).o和各個(gè)庫(kù)命令:gcc a.o(a.c) -o a 或 ld + 鏈接腳本 + 庫(kù)函數(shù)a.o -o a ,ld是匯編處理程序,a.o和其它.o和庫(kù) 目標(biāo)文件是輸入數(shù)據(jù),a是加工后數(shù)據(jù),那么我們會(huì)有一個(gè)疑問(wèn),那就是.o文件其實(shí)也是ELF 格式的呀?那他為什么還要經(jīng)過(guò)鏈接再次生成ELF格式的可執(zhí)行文件呢?如下圖解釋:ELF格式頭EL

34、F格式頭.text.rodata.data.bss其它段a.oELF格式頭.text.rodata.data.bss其它段xxx.oELF格式頭.text.rodata.data.bss其它段xxx.oELF格式頭.text.rodata.data.bss其它段x.sooELF格式頭.text.rodata.data.bss其它段xxx.a新的ELF格式頭.text.rodata.data.bss其它段a每一個(gè).o、.a和.so文件都會(huì)有自己的.text、rodata.、data.、bss等段而這.o都不能自己獨(dú)立的運(yùn)行,它們之間需要相互的支持才能運(yùn)行,所以需要做隨后的一次鏈接重新生成一個(gè)新的

35、ELF格式的可執(zhí)行文件。并且需要生成對(duì)內(nèi)存映射支持的相應(yīng)節(jié),才能加載虛擬內(nèi)存運(yùn)行那么這些段的布局格式是由鏈接腳本文件指定的,像a這種的普通文件是系統(tǒng)鏈接時(shí),由缺省鏈接腳本文件指定,我們無(wú)權(quán)指定,而普通文件鏈接的動(dòng)態(tài)庫(kù)是共享庫(kù),是別人的,需要的原因是這些庫(kù)能夠支持普通文件的運(yùn)行,沒(méi)有他們是普通文件是不能運(yùn)行的。指明了各個(gè)段的起始位置和段大小,機(jī)器大小端,機(jī)器字長(zhǎng),連接語(yǔ)法等實(shí)際上我們只有一個(gè)由a.c生成的.o,但是我們?yōu)榱撕芎玫恼f(shuō)明連接的過(guò)程,我們假定了很多的.o文件,實(shí)際上我們真的寫工程代碼的話肯定也不止只有一個(gè).o文件,上面的每個(gè).o是分別對(duì)各自的.c文件進(jìn)行預(yù)處理,編譯匯編得到的,.so是

36、動(dòng)態(tài)庫(kù),.a是靜態(tài)庫(kù),庫(kù)可以簡(jiǎn)單說(shuō)為是一堆.o文件的集合,庫(kù)的好處如下:便于模塊化功能的實(shí)現(xiàn)便于版本更新和維護(hù)不會(huì)導(dǎo)致大量無(wú)用的代碼賦值到可執(zhí)行文件中,浪費(fèi)寶貴的內(nèi)存空間靜態(tài)庫(kù)節(jié)省時(shí)間但是浪費(fèi)空間,動(dòng)態(tài)庫(kù)節(jié)省空間但是浪費(fèi)時(shí)間,側(cè)重點(diǎn)不同鏈接所做事情:符號(hào)解析:a)、符號(hào)唯一化每個(gè)符號(hào)的引用剛好和一個(gè)符號(hào)的定義聯(lián)系起來(lái),這就涉及聲明與定義的問(wèn)題,最終相同的符號(hào)會(huì)被統(tǒng)一為一個(gè),統(tǒng)一時(shí)涉及符號(hào)強(qiáng)弱問(wèn)題,函數(shù)和初始化了的全局變量為強(qiáng)符號(hào),未初始化的全局變量為弱符號(hào),符號(hào)解析時(shí),針對(duì)強(qiáng)弱符號(hào)處理規(guī)則如下:規(guī)則1:不允許多個(gè)強(qiáng)符號(hào)規(guī)則2:一個(gè)強(qiáng)符號(hào)和多個(gè)弱符號(hào),選擇強(qiáng)符號(hào),如定義全局變量int a=100

37、; 聲明int a;前者為強(qiáng),后者為弱規(guī)則3:多個(gè)都是弱符號(hào),任意選擇其中一個(gè),如果定義了兩個(gè)int a;都為初始化呢 ,兩個(gè)都是若符號(hào),選擇在程序中最靠前的一個(gè)會(huì)被合并唯一化的符號(hào)將會(huì)被組成一個(gè)集合(E集合),符號(hào)唯一化就是對(duì)E集合進(jìn)行操作b)、從其它的模塊或庫(kù)中搜索未定義符號(hào),如果到處都找不到,那么提示符號(hào)未定的錯(cuò)誤。未定義的符號(hào)組成一個(gè)集合(U集合),搜索未定義符號(hào)就是對(duì)U集合進(jìn)行操作重定位:a)、節(jié)和符號(hào)的地址重定位將所有的.o的相同節(jié)合并起來(lái),形成可執(zhí)行文件中同名的新的聚合節(jié),每個(gè)被唯一定義的符號(hào)和指令都要被賦予了運(yùn)行時(shí)地址(或也稱為連接地址,從0 x08048000開始)。重定位的

38、地址是由gcc默認(rèn)的鏈接腳本指定的,學(xué)到后面的uboot的時(shí)候鏈接腳本是自己給的,倘若給定了鏈接地址,但是又不從鏈接地址開始運(yùn)行,那么我們就說(shuō)鏈接地址和實(shí)際的運(yùn)行地址(pc實(shí)際取址)不相符合,鏈接地址和實(shí)際運(yùn)行地址不符合,這就要求運(yùn)行代碼為位置無(wú)關(guān)代碼,這和生成動(dòng)態(tài)庫(kù)時(shí),指定-fpic選項(xiàng)生成位置無(wú)關(guān)動(dòng)態(tài)庫(kù)是一個(gè)道理,如果虛擬內(nèi)存運(yùn)行起來(lái)了,pc取址的就是虛擬地址(0 x8048000就是),否者取址的就是實(shí)際物理地址,這個(gè)實(shí)際物理地址就可能會(huì)和鏈接指定的地址(一般給虛擬內(nèi)存用)不相符合,這一塊=在講uboot時(shí)會(huì)有詳細(xì)說(shuō)明的。b)、修改代碼節(jié)和數(shù)據(jù)節(jié)中對(duì)唯一定義的符號(hào)的引用,使得這些引用指向

39、正確的運(yùn)行時(shí)地址重定位相對(duì)引用地址重定位絕對(duì)應(yīng)用地址重定位依賴于重定位條目,指令重定位條目在.rel.text中,數(shù)據(jù)重定位條目在.rel.data中l(wèi)s -al a 查看文件大小-rw-rw-r-. 1 linux linux 1096 Mar 11 18:58 a.o /紅色字體是文件的大小-rwxrwxr-x. 1 linux linux 4848 Mar 11 20:20 afile a /查看文件的類型/ELF格式 32位linux standard base 可重定位文件,用于x86平臺(tái),版本1,動(dòng)態(tài)鏈接庫(kù),centos 用到的linux版本號(hào),未瘦身(包含各類符號(hào)表)a: ELF

40、 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not strippeda.o 變?yōu)閍.s后,變化如下:a)、a的大小4848,a.o大小1096,那是因?yàn)榧尤肓藙?dòng)態(tài)庫(kù)的連接信息在里面和增加了其它的節(jié)b)、都是ELF格式,但是a是ELF格式的可執(zhí)行目標(biāo)文件,并且連接了庫(kù)?ELFAAABCAPDH4?ELFAAABCAPDH4G A9r_$USd$DHtRDHCud$DUSDQlYCABhello a = %d,

41、i = %d 2 AC; C,TAzRA|HALDDA 。EANHBBMEALDD(ZANHBBMECEDCBPAAALDDP hDAPLDHMDHoDHEDHFDH a也是無(wú)法讀懂的二進(jìn)制文件,反匯編 objdump -D a u_a_a.s 2 a: file format elf32-i386 2 a: file format elf32-i386 5 Disassembly of section .interp: 6 7 08048134 : 8 8048134: 2f das 9 8048135: 6c insb (%dx),%es:(%edi) 10 8048136: 69 62

42、2f 6c 64 2d 6c imul $0 x6c2d646c,0 x2f(%edx),%esp。90 Disassembly of section .init:191 192 08048294 :193 8048294: 55 push %ebp194 8048295: 89 e5 mov %esp,%ebp。 Disassembly of section .plt:212 213 080482c4 :214 80482c4: ff 35 88 96 04 08 pushl 0 x8049688215 80482ca: ff 25 8c 96 04 08 jmp *0 x804968c21

43、6 80482d0: 00 00 add %al,(%eax)。 234 Disassembly of section .text:235 236 08048310 :237 8048310: 31 ed xor %ebp,%ebp238 8048312: 5e pop %esi239 8048313: 89 e1 mov %esp,%ecx。Disassembly of section .rodata:426 427 080484d8 :428 80484d8: 03 00 add (%eax),%eax433 80484de: 02 00 add (%eax),%al。與.o的反匯編文件基

44、本類似,但是卻有了如下的不同:被重定位后的地址不再是00000000開始,而是從08044000開始,但是有些同學(xué)可能會(huì)說(shuō)是從08048134開始的,那是因?yàn)?8044000與08048134還有部分啟動(dòng)代碼沒(méi)看見,所有的程序都是從這一地址卡是運(yùn)行的2、多了.init等的其它節(jié),后面會(huì)說(shuō)這個(gè)很重要,因?yàn)樗鼪Q定了是否能夠被加載器加載到我們的虛擬內(nèi)存中運(yùn)行可執(zhí)行文件的ELF格式我們知道了a.o的ELF格式,當(dāng)a.o被連接后會(huì)生成新的一個(gè)ELF格式的可執(zhí)行文件,其格式?jīng)]有太大變化,段名節(jié)頭部表.strtab.line.debug.symtab.bss.data.rodata.text.init段頭部表ELF頭這些信息不回加到虛擬內(nèi)存(進(jìn)程空間運(yùn)行)這些信息不回加到虛擬內(nèi)存(進(jìn)程空間運(yùn)行)數(shù)據(jù)段數(shù)據(jù)段能夠使程序被加載到內(nèi)存中運(yùn)行能夠使程序被加載到內(nèi)存中運(yùn)行代碼段代碼段決定了到虛擬內(nèi)存的映射關(guān)系,這樣我們就能夠根據(jù)它訪問(wèn)到各段和節(jié)決定了到虛擬內(nèi)存的映射關(guān)系,這樣我們就能夠根據(jù)它訪問(wèn)到各段和節(jié)上面多了藍(lán)色部分,另外少兩個(gè)節(jié),主要目的是為了將這個(gè)可執(zhí)行文件

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論