标签:
1. 初始编译器
广义的编译器 你可能不知道的事…
2. 预编译:指令示例——gcc –E file.c –o file.i
(1)处理所有的注释,以空格代替
(2)将所有的#define删除,并且展开所有的宏定义
(3)处理条件编译指令#if、#ifdef、#elif、#else、#endif
(4)处理#include,展开被包含的文件
(5)保留编译器需要使用的#pragma指令
3. 编译:指令示例——gcc –S file.i –o file.s
(1)对预处理文件进行词法分析、语法分析和语义分析
①词法分析:分析关键字、标识符、立即数等是否合法
②语法分析:分析表达式是否遵循语法规则
③语义分析:在语法分析的基础上进一步分析表达式是否合法
(2)分析结束后进行代码优化生成相应的汇编代码文件
4. 汇编:指令示例——gcc –c file.s –o file.o
(1)汇编器将汇编代码转变为机器可以执行的指令
(2)每条汇编语句几乎都对应一条机器指令
【编程实例】源代码单步编译示例
//源文件
19-1.h文件 | 19-1.c文件 |
/* This is a header file. */ char* p = "Hello World!"; int i = 0;
|
#include "19-1.h" // Begin to define macro #define GREETING "Hello world!" #define INC(x) x++ // End int main() { p = GREETING; INC(i); return 0; }
|
//第1步:预处理——gcc -E 19-1.c -o test.i
//预编译后输出的文件test.i
# 1 "19-1.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "19-1.c" # 1 "19-1.h" 1 char* p = "Hello World!"; int i = 0; # 2 "19-1.c" 2 # 11 "19-1.c" int main() { p = "Hello world!"; i++; return 0; }
//第2步:编译——gcc -S test.i -o test.s
//编译的源文件来自预编译的输出文件(test.i),编译后输出的文件为test.s
.file "19-1.c" .globl p .section .rodata .LC0: .string "Hello World!" .data .align 4 .type p, @object .size p, 4 p: .long .LC0 .globl i .bss .align 4 .type i, @object .size i, 4 i: .zero 4 .section .rodata .LC1: .string "Hello world!" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp movl $.LC1, p movl i, %eax addl $1, %eax movl %eax, i movl $0, %eax popl %ebp ret .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5" .section .note.GNU-stack,"",@progbits
//第3步:汇编——gcc -c test.s -o test.o
在第3步,会生成19-1.c文件对应的目标文件,本例中为test.o,这是一个二进制代码的文件
//第4步:链接——gcc test.o
第4步后就会生成可执行文件
5. 小结——编译过程的四个阶段:预处理、编译、汇编和链接
(1)预处理:处理注释、宏以及以#开头的符号
(2)编译:进行词法分析、语法分析和语义分析等
(3)汇编:将汇编代码翻译为机器指令的目标文件
标签:
原文地址:http://www.cnblogs.com/5iedu/p/5325360.html