一、词法分析
将源代码通过扫描器转换为记号
二、语法分析
将记号进行语法分析得到语法树(不能理解这个语句是否真的有意义)
三、语义分析
用语义分析器分析语义,只能分析静态语句
四、中间语言生成
通过源码级优化器优化掉编译期可以确定的值,得到中间代码(通常得到三地址码格式x=y op z)
五、目标代码生成和优化
通过代码生成器和目标代码优化器将中间代码转换为目标机器代码,然后通过优化器优化
到这一步,目标代码如果有变量定义在其他文件之中,其绝对地址都是在最终连接的时候才能确定的。
因为在很久之前,每次当代码改变的时候,程序员都要计算跳转指令的地址,非常容易出错,所以出现了重定位(Relocation),发明了汇编语言之后用符号(Symbol)来表示一个地址。
链接(Linking)的定义:人们把每个源代码模块独立的编译,然后按照要求将他们组装起来,这个组装的过程就是链接。链接的过程包括地址和空间分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定位(Relocation)等步骤 。
重定位:比如在A文件有个var变量,我在B文件中要给他赋值,在文件编译的时候,编译器不知道var的目标地址,所以把赋值的目标地址设置为0,等待链接器链接,然后A和B链接的时候,链接器填写var的地址,这个填写的过程被称为重定位。
一个.c文件经过编译器成为目标文件.o,中间目标文件和库一起链接形成最终可执行文件,最常见的库就是运行时库。
动态链接库(.dll .so)和静态链接库(.lib .a) 可以通过file name 命令来查看文件格式
目标文件中
段表存在于头文件之中
汇编之后的机器指令存在代码段中(.text)和(.code)
全局变量和局部静态数据存在数据段(.data)
没有初始化的变量放在.bss段中(.bss只是为未初始化的变量预留位置)
分开数据段和代码段的原因是:
可以分别设置两个段的可读和可写性能,用于防止程序被有意无意的修改。
指令区和数据区的分离可以提高程序的局部性,提高缓存命中率
当程序中运行多个该程序的副本的时候,指令部分只需要保存一份就可以了,可以节省大量内存