预处理编译汇编链接(源程序到可执行程序的四个过程)

预处理编译汇编链接(源程序到可执⾏程序的四个过程
⽂章⽬录
程序要运⾏起来,必须要经过四个步骤:预处理、编译、汇编和链接,如下图所⽰:
对于上边⽤到的⼏个选项需要说明⼀下。
使⽤ gcc 命令不跟任何的选项的话,会默认执⾏预处理、编译、汇编、链接这整个过程,如果程序没有错,就会得到⼀个可执⾏⽂件,默认为a.out。
-E选项:提⽰编译器执⾏完预处理就停下来,后边的编译、汇编、链接就先不执⾏了。
-S选项:提⽰编译器执⾏完编译就停下来,不去执⾏汇编和链接了。
-c选项:提⽰编译器执⾏完汇编就停下来。
注意 : 这三个选项限定了编译器执⾏操作的停⽌时间,⽽不是单独的将某⼀步拎出来执⾏。
1.预处理
预处理过程进⾏的操作: 将所有的“#define”删除,并且展开所有的宏定义
处理所有的条件编译指令,⽐如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”
处理“#include”预编译指令,将被包含的头⽂件插⼊到该编译指令的位置。(这个过程是递归进⾏的,因为被包含的⽂件可能还包含了其他⽂件)
删除所有的注释“//”和“/* */”。
添加⾏号和⽂件名标识,⽅便后边编译时编译器产⽣调试⽤的⾏号⼼意以及编译时产⽣编译错误或警告时能够显⽰⾏号。
保留所有的#pragma编译指令,因为编译器需要使⽤它们。
使⽤⼀个简单的程序来验证⼀下事实是否如上述所说的⼀样。编写⼀个简单的程序,然后使⽤-E选项执⾏预处理过程,打开⽣成的 .i ⽂件与源⽂件进⾏⽐对,结果⼀⽬了然,如下图所⽰:
对于给代码加上⾏号这个就不在这⾥演⽰了,我们在写代码的时候是不会⼿动添加⾏号的,我们看到的⾏号都是⾃⼰使⽤的编辑⼯具⾃动加上的,⽽这些⾏号编译系统是看不到的,但是呢,我们发现如果我们哪⼀⾏的代码出现了问题,编译的时候就会给出提⽰说哪⾏的代码有什么问题,这就已经证明,编译器是会⾃动添加⾏号的。
2.编译
使⽤-S选项,表⽰编译操作执⾏完就结束。对应⽣成⼀个 .s ⽂件。
编译过程是整个程序构建的核⼼部分,编译成功,会将源代码由⽂本形式转换成机器语⾔,编译过程
就是把预处理完的⽂件进⾏词法分析、语法分析、语义分析、中间代码⽣成和⽬标代码⽣成与优化等操作,最终形成汇编代码⽂件。
词法分析
词法分析是使⽤⼀种叫做lex的程序实现词法扫描,它会按照⽤户之前描述好的词法规则将输⼊的字符串分割成⼀个个记号。产⽣的记号⼀般分为:关键字、标识符、字⾯量(包含数字、字符串等)和特殊符号(运算符、等号等),然后他们放到对应的表中。
语法分析
语法分析器根据⽤户给定的语法规则,将词法分析产⽣的记号序列进⾏解析,然后将它们构成⼀棵语法树。对于不同的语⾔,只是其语法规则不⼀样。⽤于语法分析也有⼀个现成的⼯具,叫做:yacc。
语义分析
语法分析完成了对表达式语法层⾯的分析,但是它不了解这个语句是否真正有意义。有的语句在语法上是合法的,但是却是没有实际的意义,⽐如说两个指针的做乘法运算,这个时候就需要进⾏语义分析,但是编译器能分析的语义也只有静态语义。
静态语义
在编译期就可以确定的语义。通常包括声明与类型的匹配、类型的转换。⽐如当⼀个浮点型的表达式赋值给⼀个整型的表达式时,其中隐含⼀个从浮点型到整型的转换,⽽语义分析就需要完成这个转换,再⽐如,将⼀个浮点型的表达式赋值给⼀个指针,这肯定是不⾏的,语义分析的时候就会发现两者类型不匹配,编译器就会报错。
动态语义
只有在运⾏期才能确定的语义。⽐如说两个整数做除法,语法上没问题,类型也匹配,听着好像没⽑病,但是,如果除数是0的话,这就有问题了,⽽这个问题事先是不知道的,只有在运⾏的时候才能发现他是有问题的,这就是动态语义。
中间代码⽣成
我们的代码是可以进⾏优化的,对于⼀些在编译期间就能确定的值,是会将它进⾏优化的,⽐如说上边例⼦中的 2+6,在编译期间就可以确定他的值为8了,但是直接在语法上进⾏优化的话⽐较困难,这时优化器会先将语法树转成中间代码。中间代码⼀般与⽬标机器和运⾏环境⽆关。(不包含数据的尺⼨、变量地址和寄存器的名字等)。中间代码在不同的编译器中有着不同的形式,⽐较常见的有三地址码和P-代码。
中间代码使得编译器可以分为前端和后端。编译器前端负责产⽣于机器⽆关的中间代码,编译器后端将中间代码换成机器代码。
⽬标代码⽣成与优化
代码⽣成器将中间代码转成机器代码,这个过程是依赖于⽬标机器的,因为不同的机器有着不同的字长、寄存器、数据类型等。
最后⽬标代码优化器对⽬标代码进⾏优化,⽐如选择合适的寻址⽅式、使⽤唯⼀来代替乘除法、删除出多余的指令等。
3.汇编
汇编过程调⽤汇编器as来完成,是⽤于将汇编代码转换成机器可以执⾏的指令,每⼀个汇编语句⼏乎都对应⼀条机器指令。
使⽤命令as hello.s -o hello.o 或者使⽤gcc -c hello.s -o hello.o来执⾏到汇编过程结束,对应⽣成的⽂件是.o⽂件。
4.链接
链接的主要内容就是将各个模块之间相互引⽤的部分正确的衔接起来。它的⼯作就是把⼀些指令对其他符号地址的引⽤加以修正。链接过程主要包括了地址和空间分配、符号决议和重定位。
代码转换
符号决议
有时候也被叫做符号绑定、名称绑定、名称决议、或者地址绑定,其实就是指⽤符号来去标识⼀个地址。⽐如说 int a = 6,这样⼀句代码,⽤a来标识⼀个块4个字节⼤⼩的空间,空间⾥边存放的内容就是6。
重定位
重新计算各个⽬标的地址过程叫做重定位,重定位分为以下两步:
1. 重定位节和符号定义
合并相同类型的节,然后链接器将运⾏时的内存地址赋给新的聚合节,赋给输⼊模块定义的每个节,以及赋给输⼊模块定义的每个符号。这⼀步完成,程序中的每条指令和全局变量都有唯⼀的运⾏时内存地址了。也就是指令段与代码段中全局、静态变量、函数⼊⼝以及指令的运⾏时内存地址都已确定。
2. 重定位节中的符号引⽤
链接器修改代码节和数据节中对于每个符号的引⽤,使得他们指向正确的运⾏时地址。 这⼀步链接器依赖于可重定位⽬标模块中称为重定位条⽬的数据结构。未链接完成时⼀个模块中对于其他模块的全局变量或函数位置并不知道,⽤重定位条⽬告诉链接器在将⽬标⽂件合并成可执⾏⽂件时如何让修改这个引⽤

本文发布于:2024-09-22 14:34:10,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/4/377677.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:编译   编译器   过程   代码
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议