我们在写程序的时候,windows下通过vs等编译软件,linux通过gcc命令得到程序的可执行文件。在这个过程中,其实大致经历了4个过程。1 预编译 2 编译 3 汇编 4 链接
1 预编译:主要处理那些源代码文件中的以”#”开头的预编译指令,比如”#include”,“#define”等。
2 编译:就是把预处理完的文件进行一系列词法分析,语法分析,语义分析以及优化后生成相应的汇编代码文件
3 汇编:就是将汇编代码转变成机器可以执行的指令。
4 链接:一个工程里面包含很多.c的文件。我们最终工程得到的是.out文件。但是这个是将所有涉及到的文件都链接起来才得到的。这个就是链接的功能。
我们用一个最常见的代码来看下这几个过程
#include <stdio.h>
int main(void){
printf("hello world");
return 0;
}
gcc main.c -o main.i生成预编译文件。通过file main.i可以查看到文件的格式是ELF。这个后面会详细介绍。
root@zhf-maple:/home/zhf/c_prj# file main.i
main.i: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a19f9545eefb261b7ec7d27cf12702c3881c5ea7, not stripped
objdump -i main.i可以看到具体的内容。
通过gcc main.c -o main.s生成编译文件.objdump -S 可以查看具体的汇编代码
root@zhf-maple:/home/zhf/c_prj# objdump -S main.s
main.s: 文件格式 elf64-x86-64
Disassembly of section .init:
00000000000004f0 <_init>:
4f0: 48 83 ec 08 sub $0x8,%rsp
4f4: 48 8b 05 ed 0a 20 00 mov 0x200aed(%rip),%rax # 200fe8 <__gmon_start__>
4fb: 48 85 c0 test %rax,%rax
4fe: 74 02 je 502 <_init+0x12>
500: ff d0 callq *%rax
502: 48 83 c4 08 add $0x8,%rsp
506: c3 retq
Disassembly of section .plt:
0000000000000510 <.plt>:
510: ff 35 aa 0a 20 00 pushq 0x200aaa(%rip) # 200fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
516: ff 25 ac 0a 20 00 jmpq *0x200aac(%rip) # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
51c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000000520 <printf@plt>:
520: ff 25 aa 0a 20 00 jmpq *0x200aaa(%rip) # 200fd0 <printf@GLIBC_2.2.5>
526: 68 00 00 00 00 pushq $0x0
52b: e9 e0 ff ff ff jmpq 510 <.plt>
Disassembly of section .plt.got:
0000000000000530 <__cxa_finalize@plt>:
530: ff 25 c2 0a 20 00 jmpq *0x200ac2(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
536: 66 90 xchg %ax,%ax
Disassembly of section .text:
0000000000000540 <_start>:
540: 31 ed xor