C语言的编译和执行过程
没有系统的学过C语言,为了了解java编译流程。
先简单的略过了一下C语言的编译过程。
C语言在Linux系统下编译是有4个过程
- 预处理Pre-processing
- 编译Compilation
- 汇编Assemble
- 链接Linking
如下图所示每个过程会生成不同的文件。
这些文件会被RAM读取loading后,在系统中运行。
1.预处理Pre-processing
简单的说预处理就是处理#开头的命令。
- 删除注释: 去掉没必要的注释。
- 宏定义指令: 如#difine, #undef。(替换这些值)
- 头文件包含指令: 如#include。(直接插入include的代码)
- 条件编译指令: 如#ifdef,#ifndef,#else,#elif,#endif等。
- 特殊符号: 如在源程序中出现的#line标识将被解释为当前行号。
下面简单的写代码看一下过程。
#include <stdio.h>
#define A 10
#define B 20
int main(){
int a=A;
int b=B;
int c=a+b;
printf("%d + %d = %d\n",a,b,c);
}
创建first.i文件
$ gcc -E first.c -o first.i
查看一下first.i内容
$ cat first.i
# 1 "first.c"
# 1 "<built-in>" 1
... ...
int main(){
int a=10;
int b=20;
int c=a+b;
printf("%d + %d = %d\n",a,b,c);
}
可以看出A的值被替换了, stdio.h的内容也插入进来了。
2.编译Compilation
做完预处理后,Compiler会做编译成Assemble。
编译的过程可以分3个阶段。Front-end,Middle-end,Back-end。
Source code -> (GENERIC -> GIMPLE) -> (SSA -> RTL) -> Assembly)
2.1 Front-end
第一阶段会执行以下内容。
- 词法分析: 把C语言代码分成最小单位(token)。
- 语法分析: 用token创建Parse Tree检查语法错误。
- 语义分析: 之后检查整体语义有没有问题。比如用错变量,数据类型不一致等等…
- 中间代码生成: 生成Compile Tree。
2.2 Middle-end
这个阶段会把Compile Tree转换成SSA(Static Single Assignment)形态,
基于SSA做一些跟目标语言和结构无关的优化。
(例如,内联,常数传播,尾调用消除,冗余消除等,不会受限于CPU结构共同做的优化)。
基于SSA的优化还可以分局部优化,全局优化和循环优化。
最终生成高级语言和汇编的中间态的RTL(Register Transfer Language)。
2.3 Back-end
RTL通过RTL Optimizer再一次同时进行跟目标语言和结构无关的优化 + 相关的优化。
这次优化根据所在的结构和环境进一步做一些有效的优化。
这样最终生成汇编Assemble。
下面看看实际过程。
$ gcc -S first.i -o first.s
查看一下first.s内容
$ cat first.s
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 13
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
leaq L_.str(%rip), %rdi
movl $10, -4(%rbp)
movl $20, -8(%rbp)
movl -4(%rbp), %eax
addl -8(%rbp), %eax
movl %eax, -12(%rbp)
movl -4(%rbp), %esi
movl -8(%rbp), %edx
movl -12(%rbp), %ecx
movb $0, %al
callq _printf
xorl %ecx, %ecx
movl %eax, -16(%rbp) ## 4-byte Spill
movl %ecx, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "%d + %d = %d\n"
.subsections_via_symbols
不知道里面写的是什么内容…ㅠㅠ
3.汇编Assemble
编译完的代码,通过汇编过程编译成机器语言。
汇编的主要目的是把目标对象 ***.o
转换成有Instruction和Data的 ELF Binary format结构。
下面看看实际过程。
$ gcc -c first.s -o first.o
查看一下first.o内容
$ cat first.o
���� �� �__text__TEXTC ��__cstring__TEXTCc__compact_unwind__LDX x�__eh_frame__TEXTx@�
h$
�
PUH��H��H�=4�E�
�E��E�E�E�u�U�M��1ɉE��H��]�%d + %d = %d
CzRx
2- �$h�������CA�C
_main_printf%
用hexdump命令查看会是什么内容?
$ hexdump -C first.o
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 |................|
00000010 04 00 00 00 00 02 00 00 00 20 00 00 00 00 00 00 |......... ......|
00000020 19 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 b8 00 00 00 00 00 00 00 20 02 00 00 00 00 00 00 |........ .......|
00000050 b8 00 00 00 00 00 00 00 07 00 00 00 07 00 00 00 |................|
00000060 04 00 00 00 00 00 00 00 5f 5f 74 65 78 74 00 00 |........__text..|
00000070 00 00 00 00 00 00 00 00 5f 5f 54 45 58 54 00 00 |........__TEXT..|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 43 00 00 00 00 00 00 00 20 02 00 00 04 00 00 00 |C....... .......|
000000a0 d8 02 00 00 02 00 00 00 00 04 00 80 00 00 00 00 |................|
000000b0 00 00 00 00 00 00 00 00 5f 5f 63 73 74 72 69 6e |........__cstrin|
000000c0 67 00 00 00 00 00 00 00 5f 5f 54 45 58 54 00 00 |g.......__TEXT..|
000000d0 00 00 00 00 00 00 00 00 43 00 00 00 00 00 00 00 |........C.......|
000000e0 0e 00 00 00 00 00 00 00 63 02 00 00 00 00 00 00 |........c.......|
000000f0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000100 00 00 00 00 00 00 00 00 5f 5f 63 6f 6d 70 61 63 |........__compac|
00000110 74 5f 75 6e 77 69 6e 64 5f 5f 4c 44 00 00 00 00 |t_unwind__LD....|
00000120 00 00 00 00 00 00 00 00 58 00 00 00 00 00 00 00 |........X.......|
00000130 20 00 00 00 00 00 00 00 78 02 00 00 03 00 00 00 | .......x.......|
00000140 e8 02 00 00 01 00 00 00 00 00 00 02 00 00 00 00 |................|
00000150 00 00 00 00 00 00 00 00 5f 5f 65 68 5f 66 72 61 |........__eh_fra|
00000160 6d 65 00 00 00 00 00 00 5f 5f 54 45 58 54 00 00 |me......__TEXT..|
00000170 00 00 00 00 00 00 00 00 78 00 00 00 00 00 00 00 |........x.......|
00000180 40 00 00 00 00 00 00 00 98 02 00 00 03 00 00 00 |@...............|
00000190 00 00 00 00 00 00 00 00 0b 00 00 68 00 00 00 00 |...........h....|
000001a0 00 00 00 00 00 00 00 00 24 00 00 00 10 00 00 00 |........$.......|
000001b0 00 0d 0a 00 00 00 00 00 02 00 00 00 18 00 00 00 |................|
000001c0 f0 02 00 00 02 00 00 00 10 03 00 00 10 00 00 00 |................|
000001d0 0b 00 00 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
000001e0 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000220 55 48 89 e5 48 83 ec 10 48 8d 3d 34 00 00 00 c7 |UH..H...H.=4....|
00000230 45 fc 0a 00 00 00 c7 45 f8 14 00 00 00 8b 45 fc |E......E......E.|
00000240 03 45 f8 89 45 f4 8b 75 fc 8b 55 f8 8b 4d f4 b0 |.E..E..u..U..M..|
00000250 00 e8 00 00 00 00 31 c9 89 45 f0 89 c8 48 83 c4 |......1..E...H..|
00000260 10 5d c3 25 64 20 2b 20 25 64 20 3d 20 25 64 0a |.].%d + %d = %d.|
00000270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 43 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 |C...............|
00000290 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 |................|
000002a0 01 7a 52 00 01 78 10 01 10 0c 07 08 90 01 00 00 |.zR..x..........|
000002b0 24 00 00 00 1c 00 00 00 68 ff ff ff ff ff ff ff |$.......h.......|
000002c0 43 00 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d |C........A....C.|
000002d0 06 00 00 00 00 00 00 00 32 00 00 00 01 00 00 2d |........2......-|
000002e0 0b 00 00 00 02 00 00 15 00 00 00 00 01 00 00 06 |................|
000002f0 01 00 00 00 0f 01 00 00 00 00 00 00 00 00 00 00 |................|
00000300 07 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000310 00 5f 6d 61 69 6e 00 5f 70 72 69 6e 74 66 00 00 |._main._printf..|
00000320
嘿嘿,更看不懂…ㅠㅠ
只能推测出这是机器能看懂的机器语言吧?
4.链接Linking
通过汇编过程生成的机器语言在这个过程,链接(link)那些分别生成的包和程序。
printf()函数或 scanf()函数是已经有了已编号好标准的包。
不需要再次编译,在这次过程会跟程序链接(link)。
看看实际执行结果
$ gcc first.o -o first
最终结果的执行。
$ ./first
10 + 20 = 30
总结
C语言编译时会经过预处理,编译,汇编,链接4个过程
预处理时会将处理含有#符号的代码(注释,命令语以及特殊符号)
编译时会检查语法以及做一些优化
汇编时把代码转成机器可以看懂的机器语言
链接时把相关的包和程序链接起来,生成可执行文件。
欢迎大家的意见和交流
email: li_mingxie@163.com