C语言生成可执行文件的过程——预处理编译汇编链接。学习笔记
Posted 西邮菜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言生成可执行文件的过程——预处理编译汇编链接。学习笔记相关的知识,希望对你有一定的参考价值。
程序想要运行起来必须经过四个步骤:预处理、编译、汇编、链接。
一、预处理
将代码中的注释、宏定义、条件编译、包含头文件插入等。宏仅仅是文本替换,不会计算。
二、编译
编译是程序构建的核心部分,编译成功后生成汇编代码,编译就是对预处理后的文件进行词法分析、语法分析、语义分析以及优化。。。
词法分析:将代码分割为一个个记号,记号通常是关键字、标识符、特殊符号等等。将他们最后放到对应表中。
语法分析:将词法分析产生的符号进行解析,然后将其构成语法树。
语义分析:语法分析完成了对表达式语法层面的分析,但是它不了解这个语句是否真正有意义。有的语句在语法上是合法的,但是却是没有实际的意义,比如说两个指针的做乘法运算,这个时候就需要进行语义分析,但是编译器能分析的语义也只有静态语义。
静态语义:在编译期就可以确定的语义。通常包括声明与类型的匹配、类型的转换。比如当一个浮点型的表达式赋值给一个整型的表达式时,其中隐含一个从浮点型到整型的转换,而语义分析就需要完成这个转换,再比如,将一个浮点型的表达式赋值给一个指针,这肯定是不行的,语义分析的时候就会发现两者类型不匹配,编译器就会报错。
动态语义:只有在运行期才能确定的语义。比如说两个整数做除法,语法上没问题,类型也匹配,听着好像没毛病,但是,如果除数是0的话,这就有问题了,而这个问题事先是不知道的,只有在运行的时候才能发现他是有问题的,这就是动态语义。
程序优化:在编译期间就可以确定的值会将其优化,优化器会先将语法树转成中间代码,中间代码使得编译器可以分为前端和后端。编译器前端负责产生于机器无关的中间代码,编译器后端将中间代码换成机器代码。代码生成器将中间代码转成机器代码,这个过程是依赖于目标机器的,因为不同的机器有着不同的字长、寄存器、数据类型等。最后目标代码优化器对目标代码进行优化,比如选择合适的寻址方式、使用唯一来代替乘除法、删除出多余的指令等。
三、汇编
汇编过程调用汇编器as来完成,是用于将汇编代码转换成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。
四、链接
链接的主要内容就是将各个模块之间相互引用的部分正确的衔接起来。它的工作就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定向。
符号决议:有时候也被叫做符号绑定、名称绑定、名称决议、或者地址绑定,其实就是指用符号来去标识一个地址。比如说 int a = 6;这样一句代码,用a来标识一个块4个字节大小的空间,空间里边存放的内容就是4。
重定位:
- 将多个代码段与数据段分别合并为一个单独的代码段和数据段
- 计算每个定义的符号在虚拟地址空间中的绝对地址
- 将可执行文件中的符号引用处的地址修改为重定位后的地址信息
这个步骤可用下图来简单描述:
最基本的链接叫做静态链接,就是将每个模块的源代码文件编译成目标文件,然后将目标文件和库一起链接形成最后的可执行文件。库其实就是一组目标文件的包,就是一些最常用的代码变异成目标文件后打包存放。最常见的库就是运行时库,它是支持程序运行的基本函数的集合。
五、宏定义与const修饰的常变量的区别
1、const修饰的是个常变量有类型,宏定义的只是常量,没有数据类型。
2、define在预处理时被处理,而const是在编译运行时被处理。
3、宏定义在预处理后占用代码空间,const修饰的常变量占用数据空间。
4、const不能重定义,而宏定义可以用undef取消后重新定义。
5、宏定义不可以作为参数,而常变量可以。
以上是关于C语言生成可执行文件的过程——预处理编译汇编链接。学习笔记的主要内容,如果未能解决你的问题,请参考以下文章