编译和链接

编译和链接

整个过程

在这里插入图片描述

分为预编译,编译,汇编以及链接几个过程 以编译hello.cc为例
  1.预编译:
     1).命令 gcc -E  hello.c -o hello.i
     2).做什么: 宏展开;处理条件预编译如"#if" ; 处理#include指令,将被包含的文件插入到预编译指令的位置,递归的包含文件;  删除注释;  添加行号和文件名标识,便于调试;保留**#pragma编译器**指令(它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作 例如 #pragma message("消息文本")   当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。) ; 
     3).可以在这个hello.i查看是否你定义的宏是正确的
  2.编译:
      1).命令: gcc -S hello.i -o hello.s 或者预编译和编译一起 gcc -S hello.c -o hello.s
      2).做什么 : 生成汇编码  有以下几个步骤:词法分析;语法分析 ;语义分析 ;中间语言生成 ; 目标代码生成与优化
         1)). 词法分析: 将源代码输入扫描器,将代码字符序列分割成一系列记号
         2)).语法分析:语法分析器( Grammar Parser)将对由扫描器产生的记号进行语法分析,从而产生语法树( Syntax Tree); 简单地讲,由语法分析器生成的语法树就是以表达式( Expression)为节点的树。上面例子中的语句就是一个由赋值表达式、加法表达式、乘法表达式、数组表达式、括号表达式组成的复杂语句。它在经过语法分析器以后形成如图2-3所示的语法树。
         ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190515221414669.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3MjMyMjI4,size_16,color_FFFFFF,t_70)
         符号和数字是最小的表达式,它们不是由其他的表达式来组成的,所以它们通常作为整个语法树的叶节点。在语法分析的同时,很多运算符号的优先级和含义也被确定下来了。比如乘法表达式的优先级比加法高,而圆括号表达式的优先级比乘法高,等等。另外有些符号具有多重含义,比如星号*在C语言中可以表示乘法表达式,也可以表示对指针取内容的表达式,所以语法分析阶段必须对这些内容进行区分。**如果出现了表达式不合法,比如各种括号不匹等,编译器就会报告语法分析阶段的错误。**
        3)).语义分析:接下来进行的是语义分析,由语义分析器( Semantic Analyzer)来完成。语法分析仅仅是完成了对表达式的语法层面的分析,但是它并不了解这个语句是否真正有意义。比如C语言里面两个指针做乘法运算是没有意义的,但是这个语句在语法上是合法的;比如同样个指针和一个浮点数做乘法运算是否合法等。**编译器所能分析的语义是静态语义( Static Semantic)**,所谓静态语义是指在编译期可以确定的语义,与之对应的**动态语义( Dynamic Semantic)就是只有在运行期才能确定的语义**。
   静态语义通常包括声明和类型的匹配,类型的转换。比如当一个浮点型的表达式赋值给个整型的表达式时,其中隐含了一个浮点型到整型转换的过程,语义分析过程中需要完成这个步骤比如将一个浮点型赋值给一个指针的时候,**语义分析程序会发现这个类型不匹配编译器将会报错。动态语义一般指在运行期出现的语义相关的问题,比如将0作为除数是一个运行期语义错误。**
   ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190515221910645.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3MjMyMjI4,size_16,color_FFFFFF,t_70)
     4)).中间语言生成 : 由源代码级优化器完成,编译期就可以确定的值会进行优化;中间代码使得编译器可以被分为前端和后端。编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。这样对于一些可以跨平台的编译器而言,它们可以针对不同的平台使用同一个前端和针对不同机器平台的数个后端
     ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190515222440948.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3MjMyMjI4,size_16,color_FFFFFF,t_70)
         5)).目标代码生成与优化:
             源代码级优化器产生中间代码标志着下面的过程都属于编辑器后端。编译器后端主要包括代码生成器( Code Generator)和目标代码优化器( Target Code Optimizer)。让我们先来看看代码生成器。代码生成器将中间代码转换成目标机器代码,这个过程十分依赖于目标机器,因为不同的机器有着不同的字长、寄存器、整数数据类型和浮点数数据类型等。对于上面例子中的中间代码,代码生成器可能会生成下面的代码序列(我们用x86的汇编语言来表示,并且假设 index的类型为int型,aray的类型为int型数组;
             ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190515222730723.png)
             最后目标代码优化器对上述的目标代码进行优化,比如选择合适的寻址方式、使用位移来代替乘法运算、删除多余的指令等。上面的例子中,乘法由一条相对复杂的基址比例变址寻址( Base Index Scale Addressing)的lea指令完成,随后由一条mov指令完成最后的赋值操作,这条mov指令的寻址方式与lea是一样的
          ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190515222737525.png)
  3.汇编:
      1).命令: gcc -c hello.s  -o hello.o 或者 as hello.s -o hello.o 或者  gcc -c hello.c  -o hello.o 
      2).做什么:将汇编码变成机器码(有汇编指令到机器指令的对照表)
  4.静态链接:
      1).命令: ld -static /usr/lib/crtl.o  /usr/lib/crti.o  /usr/lib/gcc/i486-linux-gnu/4.1.3/crtbeginT.o -L /usr/lib/gcc/i486-linux-gnu/4.1.3/ -L/usr/lib  -L/lib hello.o --start-group -lgcc -lgcc_eh -lc --end-group   /usr/lib/gcc/i486-linux-gnu/4.1.3/crtend.o   /usr/lib/crtn.o
      2).做什么: 链接目标文件为最终的可执行文件; 模块独立编译但又相互引用,组装模块成最终的目标的过程是链接;   从原理来说,他的工作就是把一些指令对其他符号的地址引用加以修正;
      3).过程包括:地址额空间分配 、符号决议 、重定位等;
       解释重定位:当模块b需要访问a中的函数foo时,在未链接以前,会将foo的地址置为0,在ab连接时连接器就会将这个指令的目标地址修改为foo的正确地址。修正地址的过程叫重定位,修正的地方叫重定位入口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值