您好,登录后才能下订单哦!
在C语言编程中,源代码文件(通常以.c
为扩展名)需要经过编译器的处理才能生成可执行文件。编译过程涉及多个步骤,每个步骤都会生成不同类型的中间文件。本文将详细探讨C语言源文件编译后生成的文件类型及其作用,帮助读者深入理解C语言编译过程。
C语言的编译过程通常分为以下几个阶段:
每个阶段都会生成相应的中间文件,最终生成可执行文件。下面我们将逐一介绍每个阶段生成的文件。
预处理器是编译过程的第一步,主要负责处理源代码中的预处理指令。常见的预处理指令包括#include
、#define
、#ifdef
等。预处理器会根据这些指令对源代码进行修改,生成一个经过预处理的源代码文件。
在预处理阶段,编译器会生成一个扩展名为.i
的文件。这个文件包含了经过预处理的源代码,所有的宏定义已经被展开,所有的#include
指令已经被替换为相应的头文件内容。
例如,假设我们有一个名为main.c
的源文件,经过预处理后会生成一个main.i
文件。
gcc -E main.c -o main.i
main.i
文件的内容通常比原始源文件大得多,因为它包含了所有被包含的头文件内容。例如:
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 392 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 393 "/usr/include/features.h" 2 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 394 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4
...
在编译阶段,编译器将预处理后的源代码(.i
文件)转换为汇编代码。汇编代码是一种低级语言,与机器指令一一对应,但仍然是人类可读的。
在编译阶段,编译器会生成一个扩展名为.s
的文件。这个文件包含了与源代码对应的汇编代码。
例如,继续以main.c
为例,经过编译后会生成一个main.s
文件。
gcc -S main.i -o main.s
main.s
文件的内容是汇编代码,通常如下所示:
.file "main.c"
.section .rodata
.LC0:
.string "Hello, World!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits
在汇编阶段,汇编器将汇编代码(.s
文件)转换为机器代码,生成目标文件。目标文件包含了机器指令,但尚未进行链接,因此还不能直接执行。
在汇编阶段,编译器会生成一个扩展名为.o
的文件。这个文件是目标文件,包含了机器代码和符号表等信息。
例如,继续以main.c
为例,经过汇编后会生成一个main.o
文件。
gcc -c main.s -o main.o
目标文件(.o
文件)是二进制文件,通常不可直接阅读。它包含了机器指令、符号表、重定位信息等。目标文件的内容可以通过工具如objdump
或nm
来查看。
objdump -d main.o
输出示例:
main.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # b <main+0xb>
b: e8 00 00 00 00 callq 10 <main+0x10>
10: b8 00 00 00 00 mov $0x0,%eax
15: 5d pop %rbp
16: c3 retq
在链接阶段,链接器将一个或多个目标文件(.o
文件)以及库文件(如标准库)合并,生成最终的可执行文件。链接器的主要任务是解析符号引用,将各个目标文件中的代码和数据段合并,并生成可执行文件。
在链接阶段,编译器会生成一个可执行文件。在Linux系统中,可执行文件通常没有扩展名,而在Windows系统中,可执行文件的扩展名为.exe
。
例如,继续以main.c
为例,经过链接后会生成一个名为main
的可执行文件。
gcc main.o -o main
可执行文件是二进制文件,包含了机器指令、数据段、符号表、重定位信息等。可执行文件的内容可以通过工具如objdump
或readelf
来查看。
objdump -d main
输出示例:
main: file format elf64-x86-64
Disassembly of section .init:
0000000000401000 <_init>:
401000: 48 83 ec 08 sub $0x8,%rsp
401004: 48 8b 05 ed 2f 00 00 mov 0x2fed(%rip),%rax # 403ff8 <__gmon_start__>
40100b: 48 85 c0 test %rax,%rax
40100e: 74 02 je 401012 <_init+0x12>
401010: ff d0 callq *%rax
401012: 48 83 c4 08 add $0x8,%rsp
401016: c3 retq
Disassembly of section .plt:
0000000000401020 <.plt>:
401020: ff 35 e2 2f 00 00 pushq 0x2fe2(%rip) # 404008 <_GLOBAL_OFFSET_TABLE_+0x8>
401026: ff 25 e4 2f 00 00 jmpq *0x2fe4(%rip) # 404010 <_GLOBAL_OFFSET_TABLE_+0x10>
40102c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000401030 <puts@plt>:
401030: ff 25 e2 2f 00 00 jmpq *0x2fe2(%rip) # 404018 <puts@GLIBC_2.2.5>
401036: 68 00 00 00 00 pushq $0x0
40103b: e9 e0 ff ff ff jmpq 401020 <.plt>
Disassembly of section .text:
0000000000401040 <_start>:
401040: 31 ed xor %ebp,%ebp
401042: 49 89 d1 mov %rdx,%r9
401045: 5e pop %rsi
401046: 48 89 e2 mov %rsp,%rdx
401049: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40104d: 50 push %rax
40104e: 54 push %rsp
40104f: 49 c7 c0 00 11 40 00 mov $0x401100,%r8
401056: 48 c7 c1 90 10 40 00 mov $0x401090,%rcx
40105d: 48 c7 c7 36 11 40 00 mov $0x401136,%rdi
401064: ff 15 86 2f 00 00 callq *0x2f86(%rip) # 403ff0 <__libc_start_main@GLIBC_2.2.5>
40106a: f4 hlt
40106b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000401070 <deregister_tm_clones>:
401070: b8 30 40 40 00 mov $0x404030,%eax
401075: 48 3d 30 40 40 00 cmp $0x404030,%rax
40107b: 74 13 je 401090 <deregister_tm_clones+0x20>
40107d: b8 00 00 00 00 mov $0x0,%eax
401082: 48 85 c0 test %rax,%rax
401085: 74 09 je 401090 <deregister_tm_clones+0x20>
401087: ff e0 jmpq *%rax
401089: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
401090: c3 retq
401091: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
401098: 00 00 00
40109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000004010a0 <register_tm_clones>:
4010a0: be 30 40 40 00 mov $0x404030,%esi
4010a5: 48 81 ee 30 40 40 00 sub $0x404030,%rsi
4010ac: 48 c1 fe 03 sar $0x3,%rsi
4010b0: 48 89 f0 mov %rsi,%rax
4010b3: 48 c1 e8 3f shr $0x3f,%rax
4010b7: 48 01 c6 add %rax,%rsi
4010ba: 48 d1 fe sar %rsi
4010bc: 74 11 je 4010cf <register_tm_clones+0x2f>
4010be: b8 00 00 00 00 mov $0x0,%eax
4010c3: 48 85 c0 test %rax,%rax
4010c6: 74 07 je 4010cf <register_tm_clones+0x2f>
4010c8: ff e0 jmpq *%rax
4010ca: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
4010d0: c3 retq
4010d1: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1)
4010d8: 00 00 00 00
4010dc: 0f 1f 40 00 nopl 0x0(%rax)
00000000004010e0 <__do_global_dtors_aux>:
4010e0: 80 3d 49 2f 00 00 00 cmpb $0x0,0x2f49(%rip) # 404030 <__TMC_END__>
4010e7: 75 17 jne 401100 <__do_global_dtors_aux+0x20>
4010e9: 55 push %rbp
4010ea: 48 89 e5 mov %rsp,%rbp
4010ed: e8 7e ff ff ff callq 401070 <deregister_tm_clones>
4010f2: c6 05 37 2f 00 00 01 movb $0x1,0x2f37(%rip) # 404030 <__TMC_END__>
4010f9: 5d pop %rbp
4010fa: c3 retq
4010fb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
401100: f3 c3 repz retq
401102: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
401109: 00 00 00
40110c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000401110 <frame_dummy>:
401110: eb 8e jmp 4010a0 <register_tm_clones>
401112: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
401119: 00 00 00
40111c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000401120 <main>:
401120: 55 push %rbp
401121: 48 89 e5 mov %rsp,%rbp
401124: 48 8d 3d d9 0e 00 00 lea 0xed9(%rip),%rdi # 402004 <_IO_stdin_used+0x4>
40112b: e8 00 00 00 00 callq 401130 <main+0x10>
401130: b8 00 00 00 00 mov $0x0,%eax
401135: 5d pop %rbp
401136: c3 retq
401137: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40113e: 00 00
C语言源文件编译后生成的文件类型包括:
.i
文件):经过预处理的源代码文件。.s
文件):与源代码对应的汇编代码文件。.o
文件):包含机器代码和符号表的目标文件。理解这些文件的生成过程及其内容,有助于深入理解C语言的编译过程,并在调试和优化代码时提供帮助。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。