程序是如何执行起来的 — 预处理>>编译>>汇编>>链接

流程概括

一个程序想要执行起来,并不是一蹴而就的,必须经过预处理,编译,汇编,链接。了解这些较为底层的知识,可以帮助我们避开其中的一些“坑”。

流程分为四步:

  1. 预处理:展开头文件/宏替换/去掉注释/条件编译 (test.i main .i)

  2. 编译:检查语法,生成汇编 ( test.s main .s)

  3. 汇编:汇编代码转换机器码 (test.o main.o)

  4. 链接:链接到一起生成可执行程序 (a.out)

预处理

  1. 展开头文件
    在写有#include 或#include "filename"的文件中,将文件filename展开,通俗来说就是将fiename文件中的代码写入到当前文件中;

  2. 宏替换
    将定义宏展开

  3. 去掉注释

  4. 条件编译
    条件编译指令将决定哪些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。比如#pragma头文件只被包含一次

编译

编译是读取源程序(字符流),对之进行词法、语法和语义的分析,
高级语言指令转换为功能等效的汇编代码

1.词法分析

识别单词并分类。

词法分析器读入组成源程序的字符流,并将其组成有意义的词素的序列。形如<token-name, attribute-value>这样的词法单元。

词法分析的输入是源程序,输出是识别出的记号流.目的是识别单词. 至少分以下几类:关键字(保留字)、标识符、字面量、特殊符号

2.语法分析

组词成句及语法错误检查

语法分析器使用由词法分析器生成的各词法单元的第一个分量来创建树形的中间表示。该中间表示给出了词法分析产生的词法单元的语法结构。常用的表示方法是语法树,树中每个内部节点表示一个运算,而该节点的子节点表示运算的分量。

输入是词法分析器返回的记号流,输出是语法树.目的是得到语言结构并以树的形式表示.对于声明性语句,进行符号表的查填,对于可执行语句,检查结构合理的表达式运算是否有意义.

3.语义分析

分析各种语法成分的语义特征

语义分析器使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致 。它同时收集类型信息,并存放在语法树或符号表中,以便在中间代码生成过程使用。

语义分析的一个重要部分就是类型检查。比如很多语言要求数组下标必须为整数,如果使用浮点数作为下标,编译器就必须报错。再比如,很多语言允许某些类型转换,称为自动类型转换。

根据语义规则对语法树中的语法单元进行静态语义检查,如类型检查和转换等,目的在于保证语法正确的结构在语义分析上也是合法的.

进行分析完毕之后会生成汇编代码

但是,在分析完毕和生成汇编代码中间,可能有会有两步操作,生成介于高级语言和汇编语言的中间代码以及进行中间代码优化, 目的是为了优化程序的占用空间,执行时间。(优化循环,全部与局部的一些优化)

汇编

汇编实际上指把汇编语言代码翻译成目标机器指令的过程,生成目标文件。

目标文件中所存放的也就是与源程序等效的目标的机器语言代码。
目标文件由段组成。通常一个目标文件中至少有两个段:

代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

链接

链接程序的主要工作就是将有关的目标文件彼此相连接
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

猜你喜欢

转载自blog.csdn.net/ifwecande/article/details/107846025
今日推荐