C 语言从源码生成指令序列(二进制执行文件)经过以下过程:预处理 --> 编译 --> 汇编 --> 链接 --> 执行
一、预处理
预处理就是复制粘贴过程,去掉无需编译的代码,包括注释,行尾的 \ 链接处理,条件编译的#ifdef、#ifnde 语句。
二、编译
编译的过程有一下几个阶段:词法分析,语法分析,语义分析,中间代码生成,优化,目标代码分析
- 词法分析:记录关键、常数、字符串、运算符、大括号……并记录位置。
- 语法分析:反应程序层次结构(树状结构),报告语法错误(漏分号)。
- 语义分析:算数类型转换,报告未定义引用,运算符类型操作不匹配。
- 静态程序分析:不运行程序情况下分析语法错误。
- 中间代码生成:中间代码(IR 状态机)是面向编译场景的指令集(理解成状态机)。
- 优化:优化的目的是为了状态少(变量少),激励事件少(语句少),尽可能简化。典型例子就是 volatile 关键字的应用。
- 目标代码生成:将中间代码(IR 状态机)翻译成有处理器的 ISA 状态机。
三、汇编
根据指令集手册,把编译后的汇编代码(指令的符号化表示)翻译成二进制目标文件(指令的编码表示)、二进制文件(.o 文件)不能用文本编辑器打开。
四、链接
裸机平台:将众多的 .o 文件通过链接脚本,链接到一个指定的内存地址,最后生成 .elf 文件,通过 .elf 文件中描述的数据布局规则生成 .bin 文件,有了我们期望的数据布局之后,程序就会访问正确地址里面的数据。
操作系统平台:将众多的 .o 文件通过链接脚本,链接到一个指定的内存地址,最后生成可执行文件。
链接过程中,程序被划分为多个段(sections
),每个段存储不同类型的数据或指令。以下是常见的段:
.text
段存储程序的代码指令,包括函数实现、程序逻辑、跳转指令等内容。它的特点是只读且可执行,程序运行时,CPU