程序编译过程
程序编译过程
version : v1.0 「2022.7.28」 最后补充
author: Y.Z.T.
简介: 简单程序的编译过程
1️⃣ 编译流程
程序的整个编译流程大致分成几个阶段:
- 预处理 : 将预处理指令进行处理 , 预处理器将源文件(.c) 经过预处理变成 文件(.i )
- 编译 : 编译器调用解析工具 , 将预处理后的源文件( .i )编译成汇编文件( .s)
- 汇编 : 这是也是编译的第二阶段 , 通过汇编器将汇编文件( .s) 汇编成可重定位的目标文件( .o)
- 链接 : 将各个目标文件( .o)链接成可执行文件( 也是可执行文件的一种 )
程序编译 , 链接流程图:
2️⃣ 可执行文件
一个可执行文件通常由一系列不同的段(section)
构成:代码段、数据段、BSS段、只读数据段等。
C语言到可执行文件 :
- 函数 翻译成二进制指令放在 代码段 中
- 初始化的全局变量 和 静态局部变量 放在 数据段 中(.data)
- 未初始化的全局变量 和 静态变量 放在 BSS段 中(.bss)
- 程序中定义的一些字符串 , printf函数打印的字符串常量放在 只读数据段( .rodata) 中
3️⃣ 预处理
预处理过程 就是 在编译源程序之前 , 先处理源文件中的各种预处理指令
预处理主要包括以下操作 :
- 头文件展开: 将
#include
包含的头文件内容展开到当前位置 , 并删除#include
- 宏展开: 展开所有的宏定义,并删除
#define
。 - 条件编译: 根据宏定义条件,选择要参与编译的分支代码,其余的分支丢弃。
- 删除注释。
- 添加行号和文件名标识: 编译过程中根据需要可以显示这些信息。
- 保留
#pragma
命令: 该命令会在程序编译时指示编译器执行一些特定行为。
4️⃣ 编译
汇编过程主要包括以下步骤 :
-
词法分析
-
语法分析
-
语义分析
-
中间代码生成
-
汇编代码生成
-
目标代码生成
4.1 词法分析
词法分析主要用来解析C程序语句 , 词法分析一般会通过词法扫描器从左到右 , 将源程序分解为一系列不能再分解的记号单元–token。
常见token
- C语言的各种 关键字 :
int
,float
、for
,while
、break
等。 - 用户定义的各种 标识符 : 函数名、变量名、标号等。
- 字面量: 数字、字符串等。
- 运算符: C语言标准定义的40多个运算符。
- 分隔符: 程序结束符分号、for循环中的等
示例:
1 | sum = a + b / c; |
如上所示:
- 经过词法分析后 分解成
sum
,=
,a
,+
,b
,/
,c
,;
八个token
- 如果程序出现中文符号、圆角\半角字符 等 ,程序就会在这个阶段发错编译错误
4.2 语法分析
语法分析主要是对前一阶段产生的
token
序列进行解析, 看是否能构建成一个语法上正确的语法短语(程序、语句、表达式等)。
说明:
- 词法分析语法分析工具在对
token
序列分析过程中, 如果发现不能构建语法上正确的语句或表达式,就会报语法错误:syntax error
- 如果程序语句后 少了 **结束分号 ** 或 循环中少了分号 ,就会在此阶段产生编译错误
4.3 语义分析
语义分析主要对语法分析输出的各种表达式、语句进行检查,看看有没有错误。
例如 :
- 传递给函数的实参与函数声明的形参类型不匹配,
- 使用了一个未声明的变量
- 除数为零了;
break
在循环语句或switch
语句之外出现了,- 在循环语句之外发现了
continue
语句等
4.4 生成中间代码
说明:
- 中间代码是一维线性结构 , 类似伪代码
- 通过中间代码 , 可以很容易的将中间代码翻译成汇编代码
示例:
1 | int main(void) |
转换为中间代码 三地址码:
1 | main () |
中间代码转换为 汇编代码 :
1 | MOV R0, #2 |
- 将变量变量a、b、c分别放到寄存器R0、R1、R2中,
- 临时变量
D.4427
使用R3代替,然后使用ADD
命令完成累加。
4.5 汇编过程
- 汇编器主要是 将汇编代码翻译成对应的二进制指令;
- 同时生成一些必要的信息 , 以section的形式组装到目标文件中
汇编过程:
5️⃣ 链接过程
- 编译器在编译一个项目时,是以C源文件为单位进行编译的,每一个源文件编译生成一个对应的目标文件(.o)
- 但这些单独的目标文件(.o)是不可执行的 , 属于可重定位的目标文件;
- 它们要经过链接器 重定位 、链接 之后,才能组装成一个可执行的目标文件a.out。
- 链接器将各个目标文件组装在一起后, 重新 修改 各个目标文件中的变量或函数的 地址 ,这个过程一般称为 重定位 。
- 链接过程中 , 将各个目标文件分段组装 ; 例如 : 将各个目标文件的代码段放在一起,作为最终生成的可执行文件的代码段; 将各个目标文件的数据段放在一起,作为可执行文件的数据段。
-------------已经到底啦! -------------