说明:这是程序员的自我修养1书的读书总结,随着浏览的推动,逐渐增加内容。
分为4个步骤:
处理源代码中以#开始的预编译指令,进行宏定义展开,处理所有条件预编译指令,将被包括文件插入到预编译指令的位置,删除所有注释,添加行号及文件标识,保存#pragma编译器指令,由于编译器需用到。
进行1系列词法分析,语法分析,语义分析及优化后生成汇编代码文件。
将汇编代码转变成机器可履行的指令,生成的是目标文件
将目标文件和所包括的库文件等链接到1起生成终究的可履行文件。
从源代码开始,输入到扫描器(scanner)中,进行词法分析(应用类似有限状态机的算法),分割为1系列的记号(Token)。然落后行语法分析,产生语法树,采取上下文无关语法的分析手段。以后进行语义分析,由语义分析器完成,语法分析仅仅完成了对表达式的语法层面上的分析,但其实不了解语句是不是真正成心义。编译器能分析的语义是静态语义,在编译期可以肯定的语义。而动态语义只有在运行期才能肯定。静态语义通常包括声明和类型匹配,类型转换。动态语义1般指在运行期出现的语义相干的问题,比如讲0作为除数是1个运行期语义毛病。然后是中间语言生成,即源码级优化器,在原代码级别进行优化,此时依然是与目标机器和运行时环境无关的,其实不包括数据尺寸、变量地址和寄存器的名字。中间代码情势很多,常见的有3地址码,表示两个地址上的数据进行某项操作,赋值给另外一个地址上。中间代码使得编译器可以被分为前端和后端,编译器前端负责产生与机器无关的中间代码,后端负责将中间代码转换为目标代码,所以对1些跨平台的编译器而言,他们可以针对不同的平台使用同1个前端和针对不同机器的数个后端。以后是代码生成器和目标代码优化器,对应的都是编译器的后端,代码生成器将中间代码转换为目标机器代码,此进程10分依赖目标机器,由于不同的机器有着不同的字长、寄存器、整数数据类型和浮点数据类型等。最后目标代码优化器对目标代码进行优化,选择适合的寻址方式,使用位移代替乘法,删除过剩指令等。这个目标代码中变量地址还没有肯定,而且如果函数或变量是定义在其他模块呢时呢?定义在其他模块的全局变量和函数在终究运行时的绝对地址都要在终究链接的时候才能肯定。现代编译器可以将1个源代码文件编译成1个未链接的目标文件,然后由链接器终究将这些目标文件连接起来构成可履行文件。
重定位,符号,用来表示1个地址,既多是1个变量的起始地址,也能是1段代码或函数的起始地址。访问函数需要知道目标函数的地址,访问变量需要知道目标变量的地址,两种方式可以归结为1种方式,那就是模块间符号的援用,依托符号来通讯,类似拼图版,定义符号的模块多出1块区域,援用该符号的模块恰好少了那1块,二者的拼接恰好完善组合,这个拼接进程就是“链接”。
链接的主要内容是把各个模块之间相互援用的部份处理好,使得各个模块之间能够正确链接。
主要包括:地址和空间分配,符号决议和重定位等步骤。
符号决议也被叫做符号绑定,名称绑定,名称决议,地址绑定,指令绑定等。决议更偏向于静态链接,绑定更偏向于动态链接。
最基本的静态链接进程:
每一个模块的源代码经过编译器编译成目标文件(.o或.obj),目标文件和库1起链接构成终究可履行文件。最多见的库就是运行时库,runtime library,指的是支持程序运行的基本函数的集合。库实际上是1组目标文件的包,就是1些最经常使用的代码编译成目标文件后打包寄存。
编译器编译的时候每一个模块都是单独编译的,其实不知道具体调用的函数入口地址,使用链接器可以直接援用其他模块的函数和全局变量而无需知道它们的地址,由于链接器在链接的时候会根据使用的符号,自动去相应的目标文件中查找对应的地址,然后将援用到的符号地址重新修正,这就是静态链接的最基本的进程和作用。地址修正的进程被叫做重定位Relocation,每一个被修正的地方叫1个重定位入口Relocation Entry。重定位所做的就是给程序中每个这样的绝对地址援用的位置打补钉,是他们指向正确的地址。
上一篇 iOS开发相关资源