C 語言編程 — 程序的裝載與運行

      網友投稿 896 2025-04-02

      目錄

      文章目錄

      目錄

      文章目錄

      C 程序在操作系統中的裝載與運行

      ELF 文件

      反匯編 ELF 文件

      文章目錄

      《C 語言編程 — GCC 工具鏈》

      《C 語言編程 — 程序的編譯流程》

      《C 語言編程 — 靜態庫、動態庫和共享庫》

      《C 語言編程 — 程序的裝載與運行》

      《計算機組成原理 — 指令系統》

      《C 語言編程 — 結構化程序流的匯編代碼與 CPU 指令集》

      C 程序在操作系統中的裝載與運行

      一個程序在操作系統上運行需要經歷以下階段:

      第一階段:得到可執行文件

      編譯(Compile)

      匯編(Assemble)

      鏈接(Link)

      第二階段:裝載運行

      裝載器(Loader)將可執行文件載入到內存

      CPU 從內存中可執行文件的程序入口開始讀取指令和數據,開始真正執行程序。

      編譯和匯編的過程在上文中已經提到了,下面再繼續介紹鏈接的過程。

      子程序

      // add_lib.c int add(int a, int b) { return a+b; }

      1

      2

      3

      4

      5

      6

      主函數

      // link_example.c #include int main() { int a = 10; int b = 5; int c = add(a, b); printf("c = %d\n", c); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      編譯 C 程序得到 Object 文件

      $ gcc -g -c add_lib.c link_example.c

      1

      鏈接上述兩個 Object 文件得到一個可執行文件

      $ gcc -o link-example add_lib.o link_example.o $ ./link-example c = 15

      1

      2

      3

      4

      區別于 Object 文件,真正的可執行文件的內容如下:

      $ objdump -d -M intel -S link-example link-example: file format elf64-x86-64 Disassembly of section .init: 00000000004003c8 <_init>: 4003c8: 48 83 ec 08 sub rsp,0x8 4003cc: 48 8b 05 25 0c 20 00 mov rax,QWORD PTR [rip+0x200c25] # 600ff8 <__gmon_start__> 4003d3: 48 85 c0 test rax,rax 4003d6: 74 05 je 4003dd <_init+0x15> 4003d8: e8 43 00 00 00 call 400420 <.plt.got> 4003dd: 48 83 c4 08 add rsp,0x8 4003e1: c3 ret Disassembly of section .plt: 00000000004003f0 <.plt>: 4003f0: ff 35 12 0c 20 00 push QWORD PTR [rip+0x200c12] # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 4003f6: ff 25 14 0c 20 00 jmp QWORD PTR [rip+0x200c14] # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 4003fc: 0f 1f 40 00 nop DWORD PTR [rax+0x0] 0000000000400400 : 400400: ff 25 12 0c 20 00 jmp QWORD PTR [rip+0x200c12] # 601018 400406: 68 00 00 00 00 push 0x0 40040b: e9 e0 ff ff ff jmp 4003f0 <.plt> 0000000000400410 <__libc_start_main@plt>: 400410: ff 25 0a 0c 20 00 jmp QWORD PTR [rip+0x200c0a] # 601020 <__libc_start_main@GLIBC_2.2.5> 400416: 68 01 00 00 00 push 0x1 40041b: e9 d0 ff ff ff jmp 4003f0 <.plt> Disassembly of section .plt.got: 0000000000400420 <.plt.got>: 400420: ff 25 d2 0b 20 00 jmp QWORD PTR [rip+0x200bd2] # 600ff8 <__gmon_start__> 400426: 66 90 xchg ax,ax Disassembly of section .text: 0000000000400430 <_start>: 400430: 31 ed xor ebp,ebp 400432: 49 89 d1 mov r9,rdx 400435: 5e pop rsi 400436: 48 89 e2 mov rdx,rsp 400439: 48 83 e4 f0 and rsp,0xfffffffffffffff0 40043d: 50 push rax 40043e: 54 push rsp 40043f: 49 c7 c0 f0 05 40 00 mov r8,0x4005f0 400446: 48 c7 c1 80 05 40 00 mov rcx,0x400580 40044d: 48 c7 c7 31 05 40 00 mov rdi,0x400531 400454: e8 b7 ff ff ff call 400410 <__libc_start_main@plt> 400459: f4 hlt 40045a: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0] 0000000000400460 : 400460: b8 37 10 60 00 mov eax,0x601037 400465: 55 push rbp 400466: 48 2d 30 10 60 00 sub rax,0x601030 40046c: 48 83 f8 0e cmp rax,0xe 400470: 48 89 e5 mov rbp,rsp 400473: 77 02 ja 400477 400475: 5d pop rbp 400476: c3 ret 400477: b8 00 00 00 00 mov eax,0x0 40047c: 48 85 c0 test rax,rax 40047f: 74 f4 je 400475 400481: 5d pop rbp 400482: bf 30 10 60 00 mov edi,0x601030 400487: ff e0 jmp rax 400489: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] 0000000000400490 : 400490: b8 30 10 60 00 mov eax,0x601030 400495: 55 push rbp 400496: 48 2d 30 10 60 00 sub rax,0x601030 40049c: 48 c1 f8 03 sar rax,0x3 4004a0: 48 89 e5 mov rbp,rsp 4004a3: 48 89 c2 mov rdx,rax 4004a6: 48 c1 ea 3f shr rdx,0x3f 4004aa: 48 01 d0 add rax,rdx 4004ad: 48 d1 f8 sar rax,1 4004b0: 75 02 jne 4004b4 4004b2: 5d pop rbp 4004b3: c3 ret 4004b4: ba 00 00 00 00 mov edx,0x0 4004b9: 48 85 d2 test rdx,rdx 4004bc: 74 f4 je 4004b2 4004be: 5d pop rbp 4004bf: 48 89 c6 mov rsi,rax 4004c2: bf 30 10 60 00 mov edi,0x601030 4004c7: ff e2 jmp rdx 4004c9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] 00000000004004d0 <__do_global_dtors_aux>: 4004d0: 80 3d 55 0b 20 00 00 cmp BYTE PTR [rip+0x200b55],0x0 # 60102c <_edata> 4004d7: 75 11 jne 4004ea <__do_global_dtors_aux+0x1a> 4004d9: 55 push rbp 4004da: 48 89 e5 mov rbp,rsp 4004dd: e8 7e ff ff ff call 400460 4004e2: 5d pop rbp 4004e3: c6 05 42 0b 20 00 01 mov BYTE PTR [rip+0x200b42],0x1 # 60102c <_edata> 4004ea: f3 c3 repz ret 4004ec: 0f 1f 40 00 nop DWORD PTR [rax+0x0] 00000000004004f0 : 4004f0: 48 83 3d 28 09 20 00 cmp QWORD PTR [rip+0x200928],0x0 # 600e20 <__JCR_END__> 4004f7: 00 4004f8: 74 1e je 400518 4004fa: b8 00 00 00 00 mov eax,0x0 4004ff: 48 85 c0 test rax,rax 400502: 74 14 je 400518 400504: 55 push rbp 400505: bf 20 0e 60 00 mov edi,0x600e20 40050a: 48 89 e5 mov rbp,rsp 40050d: ff d0 call rax 40050f: 5d pop rbp 400510: e9 7b ff ff ff jmp 400490 400515: 0f 1f 00 nop DWORD PTR [rax] 400518: e9 73 ff ff ff jmp 400490 000000000040051d : // add_lib.c int add(int a, int b) { 40051d: 55 push rbp 40051e: 48 89 e5 mov rbp,rsp 400521: 89 7d fc mov DWORD PTR [rbp-0x4],edi 400524: 89 75 f8 mov DWORD PTR [rbp-0x8],esi return a+b; 400527: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 40052a: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] 40052d: 01 d0 add eax,edx } 40052f: 5d pop rbp 400530: c3 ret 0000000000400531

      : // link_example.c #include int main() { 400531: 55 push rbp 400532: 48 89 e5 mov rbp,rsp 400535: 48 83 ec 10 sub rsp,0x10 int a = 10; 400539: c7 45 fc 0a 00 00 00 mov DWORD PTR [rbp-0x4],0xa int b = 5; 400540: c7 45 f8 05 00 00 00 mov DWORD PTR [rbp-0x8],0x5 int c = add(a, b); 400547: 8b 55 f8 mov edx,DWORD PTR [rbp-0x8] 40054a: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 40054d: 89 d6 mov esi,edx 40054f: 89 c7 mov edi,eax 400551: b8 00 00 00 00 mov eax,0x0 400556: e8 c2 ff ff ff call 40051d 40055b: 89 45 f4 mov DWORD PTR [rbp-0xc],eax printf("c = %d\n", c); 40055e: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc] 400561: 89 c6 mov esi,eax 400563: bf 10 06 40 00 mov edi,0x400610 400568: b8 00 00 00 00 mov eax,0x0 40056d: e8 8e fe ff ff call 400400 } 400572: c9 leave 400573: c3 ret 400574: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 40057b: 00 00 00 40057e: 66 90 xchg ax,ax 0000000000400580 <__libc_csu_init>: 400580: 41 57 push r15 400582: 41 89 ff mov r15d,edi 400585: 41 56 push r14 400587: 49 89 f6 mov r14,rsi 40058a: 41 55 push r13 40058c: 49 89 d5 mov r13,rdx 40058f: 41 54 push r12 400591: 4c 8d 25 78 08 20 00 lea r12,[rip+0x200878] # 600e10 <__frame_dummy_init_array_entry> 400598: 55 push rbp 400599: 48 8d 2d 78 08 20 00 lea rbp,[rip+0x200878] # 600e18 <__init_array_end> 4005a0: 53 push rbx 4005a1: 4c 29 e5 sub rbp,r12 4005a4: 31 db xor ebx,ebx 4005a6: 48 c1 fd 03 sar rbp,0x3 4005aa: 48 83 ec 08 sub rsp,0x8 4005ae: e8 15 fe ff ff call 4003c8 <_init> 4005b3: 48 85 ed test rbp,rbp 4005b6: 74 1e je 4005d6 <__libc_csu_init+0x56> 4005b8: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0] 4005bf: 00 4005c0: 4c 89 ea mov rdx,r13 4005c3: 4c 89 f6 mov rsi,r14 4005c6: 44 89 ff mov edi,r15d 4005c9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 4005cd: 48 83 c3 01 add rbx,0x1 4005d1: 48 39 eb cmp rbx,rbp 4005d4: 75 ea jne 4005c0 <__libc_csu_init+0x40> 4005d6: 48 83 c4 08 add rsp,0x8 4005da: 5b pop rbx 4005db: 5d pop rbp 4005dc: 41 5c pop r12 4005de: 41 5d pop r13 4005e0: 41 5e pop r14 4005e2: 41 5f pop r15 4005e4: c3 ret 4005e5: 90 nop 4005e6: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 4005ed: 00 00 00 00000000004005f0 <__libc_csu_fini>: 4005f0: f3 c3 repz ret Disassembly of section .fini: 00000000004005f4 <_fini>: 4005f4: 48 83 ec 08 sub rsp,0x8 4005f8: 48 83 c4 08 add rsp,0x8 4005fc: c3 ret

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      C 語言編程 — 程序的裝載與運行

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      148

      149

      150

      151

      152

      153

      154

      155

      156

      157

      158

      159

      160

      161

      162

      163

      164

      165

      166

      167

      168

      169

      170

      171

      172

      173

      174

      175

      176

      177

      178

      179

      180

      181

      182

      183

      184

      185

      186

      187

      188

      189

      190

      191

      192

      193

      194

      195

      196

      197

      198

      199

      200

      201

      202

      203

      204

      205

      206

      207

      208

      209

      210

      211

      212

      213

      214

      215

      216

      217

      218

      219

      220

      221

      222

      可見,鏈接(Link) 不僅僅是單純的將多個 Object 文件拼湊起來而已,而是將程序真正的轉換為一個可以在操作系統上執行的文件格式,且這個文件中還包含了整個程序所有 Object 文件的內容。在 Linux 上,這個文件格式就是 ELF(Execuatable and Linkable File Format,可執行與可鏈接文件格式)。

      ELF 文件

      ELF 文件格式:是一種用于二進制文件、可執行文件、目標代碼、共享庫和核心轉儲格式文件。ELF 文件由 4 部分組成,分別是 ELF header、程序頭表(Program Header Table)、節(Section)和節頭表(Section Header Table)。

      位于 ELF Header 和 Section Header Table 之間的都是段(Section)。一個典型的 ELF 文件包含下面幾個段:

      .text:已編譯程序的指令代碼段。

      .rodata:即只讀數據(譬如常數 const)。

      .data:已初始化的C程序全局變量和靜態局部變量。

      .bss:未初始化的C程序全局變量和靜態局部變量。

      .debug:調試符號表,調試器用此段的信息幫助調試。

      可以使用 readelf -S 查看其各個 section 的信息如下:

      $ readelf -S hello There are 31 section headers, starting at offset 0x19d8: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 …… [11] .init PROGBITS 00000000004003c8 000003c8 000000000000001a 0000000000000000 AX 0 0 4 …… [14] .text PROGBITS 0000000000400430 00000430 0000000000000182 0000000000000000 AX 0 0 16 [15] .fini PROGBITS 00000000004005b4 000005b4 ……

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      在鏈接器把程序轉換為 ELF 格式的可執行文件之后,裝載器再去處理就會容易得多。因為裝載器不再需要考慮地址跳轉的問題,只需要解析 ELF 文件,把對應的指令和數據加載到內存里面供 CPU 執行就可以了。

      同樣,Windows 也有自己的可執行文件格式 PE(Portable Executable Format)。因為 Linux 和 Windows 的可執行文件格式不同,所以也就不能夠 “一次編譯,跨平臺執行” 了。那么換句話說:是不是只要在 Linux 上運行可以解析 PE 文件的裝載器就可以解決這個問題呢?答案是肯定的,Linux 著名的開源軟件 Wine 正是此類裝載器,國內很多 Linux Desktop 發行版都是基于 Wine 實現了 Windows 常用軟件的移植。

      反匯編 ELF 文件

      由于 ELF 文件無法被當做普通文本文件打開,如果希望直接查看一個 ELF 文件包含的指令和數據,需要使用反匯編的方法。

      使用 objdump -D 對其進行反匯編如下:

      $ objdump -D hello …… 0000000000400526

      : // main標簽的PC地址 //PC地址:指令編碼 指令的匯編格式 400526: 55 push %rbp 400527: 48 89 e5 mov %rsp,%rbp 40052a: bf c4 05 40 00 mov $0x4005c4,%edi 40052f: e8 cc fe ff ff callq 400400 400534: b8 00 00 00 00 mov $0x0,%eax 400539: 5d pop %rbp 40053a: c3 retq 40053b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) ……

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      使用 objdump -S 將其反匯編并且將其 C 語言源代碼混合顯示出來:

      # 要加上 -g 選項 $ gcc -o hello -g hello.c $ objdump -S hello …… 0000000000400526

      : #include int main(void) { 400526: 55 push %rbp 400527: 48 89 e5 mov %rsp,%rbp printf("Hello World!" "\n"); 40052a: bf c4 05 40 00 mov $0x4005c4,%edi 40052f: e8 cc fe ff ff callq 400400 return 0; 400534: b8 00 00 00 00 mov $0x0,%eax } 400539: 5d pop %rbp 40053a: c3 retq 40053b:

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      C 語言 匯編語言

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:怎么取消excel2007密碼保護
      下一篇:訂單管理系統(訂單信息輕松管理
      相關文章
      国产亚洲综合成人91精品 | 亚洲国产精品不卡在线电影| 国产亚洲漂亮白嫩美女在线| 亚洲欧美不卡高清在线| 亚洲人成网站在线观看播放青青| 久久久久亚洲av无码专区导航| 亚洲AV无码一区东京热久久| 亚洲乱码无码永久不卡在线| 伊人久久大香线蕉亚洲五月天 | 亚洲网站视频在线观看| 久久狠狠高潮亚洲精品| 亚洲视频国产视频| 亚洲理论片在线观看| 亚洲精品综合久久中文字幕| 亚洲精品国产肉丝袜久久| 亚洲自偷精品视频自拍| 亚洲国产精品xo在线观看| 亚洲午夜精品一区二区公牛电影院| 亚洲成人一级电影| 亚洲一欧洲中文字幕在线| 亚洲无吗在线视频| 亚洲精品无码中文久久字幕| 怡红院亚洲红怡院在线观看| 高清在线亚洲精品国产二区| 亚洲国产精品丝袜在线观看| 亚洲人成无码网WWW| 亚洲精品国产精品乱码不99| 亚洲欧洲日产国码无码久久99| 亚洲成AV人片在| 亚洲视频在线免费观看| 亚洲人成网站日本片| 亚洲字幕AV一区二区三区四区| 亚洲精品中文字幕| 亚洲成a人片在线观看久| 国产黄色一级毛片亚洲黄片大全| 亚洲熟妇av一区二区三区| 亚洲国产综合精品中文第一区| 亚洲成人免费在线观看| 亚洲丁香婷婷综合久久| 亚洲国产精品成人网址天堂 | 亚洲性猛交XXXX|