编译流程和llvm架构介绍


    第一部分 编译流程介绍

    程序从源文件变成二进制可执行文件主要分为4个步骤:预编译、编译、汇编、链接。文件的格式变化为mian.c(源文件) -> main.i(预编译后的文件) -> main.s(编译后的文件,即汇编代码) -> main.o(汇编后的文件) -> main.exe(二进制可执行文件)。

    我们广义上将实现源文件转变为可执行文件的机器称为编译器,但其实该过程主要是由四个不同的机器实现的,包括预处理器(CPP)、编译器(CCL)、汇编器(AS)、链接器(LD)。

    预处理器:主要是将源文件中的头文件编译进来,进行宏替换,去掉注释等,并将预处理后的代码交给编译器处理。

    编译器

           1. 词法分析阶段:读入经过预编译处理后的源程序,对构成源程序的字符流进行扫描和分解,识别出单词。

           2. 语法分析阶段:机器通过词法分析,将单词序列分解成不同的语法短语,确定整个输入串能够构成语法上正确的程序。

           3. 语义分析阶段:检查源程序上有没有语义错误(赋值语句左端与右端类型不匹配),在代码生成阶段收集类型信息。

           4. 中间代码生成阶段:在进行了上述的语法分析和语义分析阶段的工作之后(前面三个分析阶段主要是为了检查程序中是否由错误,只有当程序没有基础错误才能将其转变为中间代码),有的编译程序将源程序变成一种内部表示形式。

           5. 代码优化:这一阶段的任务是对前一阶段产生的中间代码进行变换或进行改造,目的是使生成的目标代码更为高效,即省时间和省空间。

           6. 目标代码生成:这一阶段的任务是把中间代码变换成特定机器上的绝对指令代码或可重定位的指令代码或汇编指令代码(生成绝对指令代码则相当于编译器把AS和LD的功能都实现了,可以理解为这个编译器中包含了汇编器和链接器的功能)。

    汇编器:将汇编代码转变为二进制可执行文件,汇编代码的每一个指令都对应一个指定的二进制字符,前辈们就是觉得直接看二进制代码太痛苦了所以将二进制字符抽象为汇编指令。

    链接器:实现符号重定位功能,将main.o中所依赖的所有外部文件全部链接到main中形成main.exe。相对于静态链接,动态链接可以节省内存和磁盘空间、程序之间的耦合度小、适合大规模软件开发、增加程序的可扩展性与兼容性,但是静态链接部署和迁移相对来说更加方便。

    编译原理中的前后端的区分应该是处理的代码是否与目标机器有关,处理操作与目标机器无关的称之为前端,与目标机器有关的那一部分操作称之为后端。所以以这种方式来区分的话,预处理阶段+编译阶段的词法、语法、语义分析、中间代码生成和代码优化可以称为前端,而编译阶段中的汇编代码生成部分+汇编阶段+链接阶段可以称为后端。

    

    第二部分 llvm及相关编译器架构介绍

    传统静态编译器(与大多数 C 编译器一样)最流行的设计是三相设计,其主要组件是前端、优化器和后端,其结构如下图所示:

    

    当编译器决定支持多种源语言或目标体系结构时,这种经典设计最重要的胜利就来了。如果编译器在其优化器中使用通用代码表示形式,则可以为可以编译到它的任何语言编写前端,也可以为可以从中编译的任何目标编写前端,结构如下图所示:

    

    GCC(GNU Compiler Collection,GNU编译器套件)也将三段式做的比较好,并且实现了很多前端,支持了很多语言。但是上述这些编译器的致命缺陷是,他们是一个完整的可执行文件,没有给其它语言的开发者提供代码重用的接口。即使GCC是开源的,但是源代码重用的难度也比较大,而llvm则可以解决这些问题。

    Clang 是一个 C、C++、Objective-C 和 Objective-C++ 编程语言的编译器前端,采用底层虚拟机(LLVM)作为后端。

    LLVM 命名最早源自于底层虚拟机(Low Level Virtual Machine)的缩写,由于命名带来的混乱,目前LLVM就是该项目的全称。LLVM 核心库提供了与编译器相关的支持,可以作为多种语言编译器的后台来使用。能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。LLVM的项目是一个模块化和可重复使用的编译器和工具技术的集合。输入LLVM Optimizer优化器中的是LLVM IR中间语言,任何语言只要实现与之对应的前端将其源代码翻译为LLVM IR中间代码,LLVM架构后端都能将其编译程成相应的二进制文件在目标机器上运行。

    LLVM 架构是作用于编译器中的,其结构如下如所示;

        

    java虚拟机一次编译可以到处运行的原理是,java前端编译器将java源代码翻译为Java bytecode,这是一种中间语言,可以被java虚拟机所识别。java虚拟机将中间代码优化后再依据其所在机器的架构将其编译为对应的二进制文件。如此就可以实现一次编译多处运行。

 

参考链接:

https://www.cnblogs.com/zuopeng/p/4141467.html

http://www.aosabook.org/en/llvm.html

https://blog.csdn.net/xhhjin/article/details/81164076

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM