了解LLVM、Clang编译过程

2023-11-01

在这里插入图片描述

LLVM 是一个自由软件项目,它是一种编译器基础设施,以 C++ 写成,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。它是为了任意一种编程语言而写成的程序,利用虚拟技术创造出编译时期、链接时期、运行时期以及“闲置时期”的最优化。它最早以 C/C++ 为实现对象,而当前它已支持包括 ActionScript、Ada、D语言、Fortran、GLSL、Haskell、Java字节码、Objective-C、Swift、Python、Ruby、Crystal、Rust、Scala 以及 C# 等语言。
– 维基百科

2000年,伊利诺伊大学厄巴纳-香槟分校(University of Illinois at Urbana-Champaign 简称UIUC)这所享有世界声望的一流公立研究型大学的 Chris Lattner(他的 twitter @clattner_llvm ) 开发了一个叫作 Low Level Virtual Machine 的编译器开发工具套件,后来涉及范围越来越大,可以用于常规编译器,JIT编译器,汇编器,调试器,静态分析工具等一系列跟编程语言相关的工作,于是就把简称 LLVM 这个简称作为了正式的名字。Chris Lattner 后来又开发了 Clang,使得 LLVM 直接挑战 GCC 的地位。2012年,LLVM 获得美国计算机学会 ACM 的软件系统大奖,和 UNIX,WWW,TCP/IP,Tex,JAVA 等齐名。
– 深入剖析 iOS 编译 Clang / LLVM

对于 iOS 开发者来说,Swift 之父 Chris Lattner 的大名应该都会有所耳闻。他和他的团队所开发的 LLVM 已经成为 iOS 乃至 macOS 整个生态中至关重要的底层基础设施。虽然 Lattner 本人已经去 Google 做人工智能了,但是对于 iOS 开发者了解并掌握一些关于 LLVM 的基本知识还是很有必要的。

LLVM 初探

LLVM 的官网是 http://llvm.org/。通过官网我们可以看到,LLVM 其实是一系列的编译组件的集合。而 Clang (标准读法是 克朗) 是作为其中的前端。这里的前端并不是 HTML5 这样的前端概念。说到这里,我们来简单回顾下传统编译器的设计吧

传统编译器

在 LLVM 诞生之前,使用最广泛的应该是 GCC 编译器了,当然,GCC 在当下仍然扮演着很重要的角色。

编译器前端 Front End

编译器前端的任务是解析源代码,具体工作内容包括下列三个流程:词法分析、语法分析、语义分析
检查源代码是否存在错误,然后构建抽象语法树(Abstract Syntax Tree, AST)。
LLVM的前端还会生成中间代码(intermediate representation, IR)。

优化器 Optimizer

优化器负责进行各种优化。改善代码的运行时间,例如消除冗余计算等。

编译器后端 Back End

将代码映射到目标指令集。生成机器语言,并且进行机器相关的代码优化。
有些资料也会把编译器后端成为 代码生成器 Code Generator。

从上面的内容可以看到,传统的编译器架构前端和后端之间耦合度太高,如果要支持一门新的编程语言,或者一个新的目标平台,工作量会非常大。

LLVM 架构

LLVM 之所以能够成为编译器中的中流砥柱,最重要的就是使用了通用的代码表现形式,也就是 IR。有了 IR,LLVM 就可以为任何编程语言独立编写前端,并且可以为任意硬件架构独立编写后端。
在这里插入图片描述

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

Clang

Clang 是 LLVM 项目中的一个子项目。它是基于 LLVM 架构的轻量级编译器,诞生之初是为了替代 GCC,提供更快的编译速度。它是负责编译 C、C++、Objective-C 语言的编译器,它属于整个 LLVM 架构中的编译器前端。对于我们来说,研究 Clang 可以让我们更深刻的理解从源码到汇编再到机器码的这一过程。

Clang 的官网地址是 http://clang.llvm.org/

相比于 GCC,Clang 具有以下优点

  • 编译速度快:在某些平台上,Clang的编译速度显著的快过GCC(Debug模式下编译OC速度比GGC快3倍)
  • 占用内存小:Clang生成的AST所占用的内存是GCC的五分之一左右
  • 模块化设计:Clang采用基于库的模块化设计,易于 IDE 集成及其他用途的重用
  • 诊断信息可读性强:在编译过程中,Clang 创建并保留了大量详细的元数据 (metadata),有利于调试和错误报告
  • 设计清晰简单,容易理解,易于扩展增强

也就是说,广义上的 LLVM 指的是整个 LLVM 架构,而狭义上的 LLVM 是指的 LLVM 后端。
而 LLVM 后端包括代码优化(优化器)和目标代码生成(后端)两个部分。

在这里插入图片描述

Clang 编译流程

在这里插入图片描述

clang -ccc-print-phases 源文件路径
  1. 输入文件:找到源文件
input, "main.m", objective-c
  1. 预处理阶段:这个过程处理包括宏的替换,头文件的导入
    这个阶段主要是处理包括宏的替换,头文件的导入,可以执行命令 clang -E 源文件路径,执行完毕可以看到头文件的导入和宏的替换。define则在预处理阶段会被替换,所以经常被是用来进行代码混淆,目的是为了 app 安全,实现逻辑是:将 app 中核心类、核心方法等用系统相似的名称进行取别名,然后在预处理阶段就被替换,来达到代码混淆的目的。
preprocessor, {0}, objective-c-cpp-output
  1. 编译阶段:进行词法分析、语法分析、检测语法是否正确,最终生成IR
  • 词法分析
    预处理完成后就会进行词法分析,这里会把代码切成一个个 token,比如大小括号、等于号、还有字符串等,
  • 语法分析
    语法分析,它的任务是验证语法是否正确,在词法分析的基础上将单词序列组合成各类此法短语,如程序、语句、表达式 等等
  • 然后将所有节点组成抽象语法树(Abstract Syntax Tree AST),语法分析程序判断程序在结构上是否正确。
  • 生成中间代码IR
    完成以上步骤后,就开始生成中间代码 IR 了,代码生成器(Code Generation)会将语法树自顶向下遍历逐步翻译成 LLVM IR
compiler, {1}, ir
  1. 后端:这里LLVM会通过一个一个的pass去优化,每个pass做一些事情,最终生成汇编代码
backend, {2}, assembler
  1. 汇编代码生成目标文件
    目标文件的生成,是汇编器以汇编代码作为插入,将汇编代码转换为机器代码,最后输出目标文件(object file)
assembler, {3}, object
  1. 链接:链接需要的动态库和静态库,生成可执行文件
    链接主要是链接需要的动态库和静态库,生成可执行文件,其中静态库会和可执行文件合并,动态库是独立的。连接器把编译生成的 .o 文件和 .dyld、.a 文件链接,生成一个 mach-o 文件
linker, {4}, image(镜像文件)
  1. 绑定:通过不同的架构,生成对应的可执行文件
bind-arch, "x86_64", {5}, image

什么是LLVM?

http://events.jianshu.io/p/1ac7feeb4ed5

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解LLVM、Clang编译过程 的相关文章

  • Asp.net core默认路由

    简化版Startup code public void ConfigureServices IServiceCollection services services AddMvc public void Configure IApplica
  • C# 和月历,选择多个日期

    我正在制作一个程序 可以帮助人们用 C 为某个部门 预订 订单 他们需要能够选择不同月份的多个日期 我更愿意拥有它 这样他们就可以单击一个日期 然后按住 Shift 键单击另一个日期以选择这两个日期之间的所有日期 并控制单击以进行单选 取消
  • 使用 Xamarin.Forms 和 Zxing 生成 QR 码

    我在网上看到了很多关于这个的内容 旧帖子 但似乎没有什么对我有用 我正在尝试从字符串中生成二维码并将其显示在应用程序中 这就是我一开始的情况 qrCode new ZXingBarcodeImageView BarcodeFormat Ba
  • OpenGL缓冲区更新[重复]

    这个问题在这里已经有答案了 目前我正在编写一个模拟水的程序 以下是我所做的步骤 创建水面 平面 创建VAO 创建顶点缓冲区对象 在其中存储法线和顶点 将指针绑定到此 VBO 创建索引缓冲区对象 然后我使用 glDrawElements 渲染
  • .pdbs 会减慢发布应用程序的速度吗?

    如果 dll 中包含 pdb 程序调试 文件 则行号将出现在引发的任何异常的堆栈跟踪中 这会影响应用程序的性能吗 这个问题与发布与调试 即优化 无关 这是关于拥有 pdb 文件的性能影响 每次抛出异常时都会读取 pdb 文件吗 加载程序集时
  • 具有多个谓词的 C++11 算法

    功能如std find if来自algorithmheader 确实很有用 但对我来说 一个严重的限制是我只能为每次调用使用 1 个谓词count if 例如给定一个像这样的容器std vector我想同时应用相同的迭代find if 多个
  • Nhibernate:连接表并从其他表获取单列

    我有以下表格 create table Users Id uniqueidentifier primary key InfoId uniqueidentifier not null unique Password nvarchar 255
  • 关闭整数的最右边设置位

    我只需要关闭最右边的设置位即可 我的方法是找到最右边位的位置 然后离开该位 我编写这段代码是为了这样做 int POS int n int p 0 while n if n 2 0 p else break n n 2 return p i
  • 名称查找、实例化点 (POI) 和基本类型

    以下代码针对 X 进行编译 但不适用于 double struct X void foo double void foo X namespace NN struct A void foo A foo double error foo not
  • 无法获取本地或参数的值,因为它在此指令指针处不可用,可能是因为它已被优化掉

    Visual Studio 2010 会删除 没有其他词 不安全块中函数参数之一中的数据 什么可能导致此错误 调试器显示以下消息 Cannot obtain value of local or argument as it is not a
  • 如何设置消息队列的所有者?

    System Messaging MessageQueue 类不提供设置队列所有权的方法 如何以编程方式设置 MSMQ 消息队列的所有者 简短的答案是 p invoke 对 windows api 函数的调用MQSetQueueSecuri
  • 如何在新窗口中打开图像或pdf文件?

    我有一个 gridview 它包含文件名和文件路径 图像和 pdf 格式文件 其中我使用了模板字段 在该字段下放置了 1 个图像按钮 单击该图像按钮 即 查看 按钮 时 我想在新窗口中打开所选文件 这是我的代码 protected void
  • 如何使用 C# 查询远程 MS ACCESS .mdb 数据库

    我正在尝试使用 C 查询 mote MS ACCESS 数据库 mdb 文件 将文件复制到本地计算机时可以成功查询它 我只想远程放置文件 所以我的客户端程序不包含原始数据 static string m path http www xyz
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 在 mvc4 中创建通用 mvc 视图

    我以前也提过类似的问题 没有得到答案 如何创建一个通用的 mvc4 视图 该视图可以显示传递给它的模型列表或单个模型 模型可以是个人 组织或团体 无论传递给它的是什么 如果您正在寻找类似的东西 model MyViewModel
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维
  • 如何调用与现有方法同名的扩展方法? [复制]

    这个问题在这里已经有答案了 我有这样的代码 public class TestA public string ColA get set public string ColB get set public string ColC get se
  • Unity,c++ 本机插件字节数组不匹配

    在我的 C 本机插件中 我有一个调用 vector
  • 运行 xunit 测试时无法将输出打印到控制台窗口

    public class test2InAnotherProject private readonly ITestOutputHelper output public test2InAnotherProject ITestOutputHel
  • IDisposable 的显式实现

    虽然有很多关于IDisposable在 SO 上找到 我还没有找到答案 我通常遵循这样的做法 当我的一个班级拥有一个IDisposable对象然后它也实现IDisposable并打电话Dispose在拥有的对象上 然而最近我遇到了一个类 它

随机推荐

  • java field_Java Field.get()取得对象的Field属性值

    首页 gt 基础教程 gt 反射 gt Reflection API Java Field get 取得对象的Field属性值 定义 public Object get Object obj 1 如果字段不是静态字段的话 要传入反射类的对象
  • win10修改系统字体(替换OneNote中Calibri字体)

    微软的OneNote还是很好用的 但是字体问题一直是一个吐槽点 我自己就去微软官网吐槽了好几次 然而并没有什么用 我说设置默认字体为consolas完全无法生效 再次输入笔记时 中文自动改为微软雅黑 英文就是Calibri 他们回复我说确实
  • 递归实现逆序输出(C)

    一 概念 程序调用自身的编程技巧称为递归 recursion 递归做为一种算法在程序设计语言中广泛应用 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法 它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
  • diffusion model(三)—— classifier guided diffusion model

    系列阅读 diffusion model 一 DDPM技术小结 denoising diffusion probabilistic diffusion model 二 DDIM技术小结 diffusion model 三 classifie
  • 公司不重视软件测试,新来的阿里P8给我们撰写了测试用例编写规范

    测试用例 Test Case 是指对一项特定的软件产品进行测试任务的描述 体现测试方案 方法 技术和策略 其内容包括测试目标 测试环境 输入数据 测试步骤 预期结果 测试脚本等 最终形成文档 1 能看懂需求文档 找准测试测试依据 作为测试人
  • 29.手把手系列之二进制部署高可用k8s集群

    29 手把手系列之二进制部署高可用k8s集群 二进制部署高可用k8s集群 本章节采用纯二进制文件方式部署https 证书有效期为10年 高可用k8s集群 所有涉及的配置文件和镜像均已提供 另外 默认集群规模可支撑254个节点 如果需要调整
  • MyBatis自定义映射resultMap

    目录 一 字段名与属性名不一致 方法一 方法二 方法三 二 处理多对一映射关系 1 级联属性赋值 用的不多 虽然简单 2 Association 3 分步查询 三 处理一对多映射关系 1 collection 2 分步查询 一 字段名与属性
  • 《成年人の骚话大全》

    现在的年轻人 骚气得很 不仅为人性格闷骚 网上冲浪时更是满嘴骚话 今天我们来看看 在网民的集体智慧下 究竟有哪一些旧词被 骚 出了新意吧 扫码关注公众号 肉眼品世界 若要问 什么东西能够准地捕捉当代人的复杂想法 同时又能让接受信息的一方快速
  • specCPU 2006 备忘

    前言 首先 specCPU是收费的 好像是800 还是1000 缴费了才有软件分发给你 关键是你要提交结果 那估计得需要购买了 因为测试报告里面有个序列号 应该是购买后给的一个号 测试的时候也要写到配置文件里 但是个人1测试或者普通项目摸底
  • 秒杀多线程第一篇 多线程笔试面试题汇总

    http blog csdn net morewindows article details 7392749
  • linux文件权限修改

    chmod u g o r w x 1 c 权限命令符 第一权限 第二权限 第三权限 加权 减权 唯一权限 读权 写权 可执行权 文件名 总权限 a all 可替换u g o R 4 w2 x1 可以用三个数字设置权限 例如777表示权限全
  • 浏览器窗口切换(从一个页面切换到另一个页面并且不刷新)

    从一个页面跳转到另一个浏览器打开过的页面 只有通过window open 打开的同源页面才能相互切换 window open javascript name 第一项参数 javascript 后可添加js 代码也会执行 第二项参数 name
  • Linux驱动入门(6.0)--- Linux驱动与设备的匹配规则

    前言 1 因为在Linux驱动开发中 驱动可以和设备c文件文件进行匹配 也可以和设备树dts文件进行匹配 为了弄明白驱动与他们的匹配规则 我查阅了一些资料同时阅读了源码 最终打算使用图片的方式形象具体的写成博客 2 网上的资料基本都大同小异
  • android 清空sp,Android SP的具体内容

    username findViewById R id username 输入账户的 password findViewById R id password 输入密码的 CheckBox checkBox findViewById R id
  • git release功能

    命令行 git tag a v3 0 m 这是4 0版本 git push origin v3 0 git tag a 标签名称 m 说明 git push origin 标签名称 删除tag git tag d v1 1 删除本地tag
  • 7-2二分查找(折半查找)

    描述 已知一个有n个元素的从小到大排列的整数序列 序列中的数据没有重复 现在要查找一个给定的值key 输出key在此序列中出现的位置 例如 在序列 1 2 3 5 8 9 12 21 37 49 55 613 中 查找5的结果是4 表示找到
  • 猜数字游戏——C语言

    写一个猜数字游戏 要求 1 自动产生一个1 100之间的数字 2 猜数字 a 猜对了 恭喜你游戏结束 b 你猜错了 告诉你猜大了 还是猜小了 继续猜 直到猜对 3 可以一直玩 直到退出游戏 游戏设计 1 游戏框架设计 menu 游戏菜单 p
  • gdb和windbg常用调试命令对照

    由于工作的需要 本人常常需要在gdb和windbg调试器上来回切换 经常会弄混淆这两者的命令 现做个对照表 方便随时查阅 本人也经常用到ollydbg 但由于od界面很友好 不太需要用到命令 况且od的命令插件都是根据windbg做的 所以
  • Hive parquet数据格式内部结构

    parquet是一个列式存储格式 对于大型查询 指定列查询都是高效的 内部由一个header 四个block 一个footer组成 header中只包含一个4个字节的数字PAR1用来识别整个Parquet文件格式 文件中所有的metadat
  • 了解LLVM、Clang编译过程

    LLVM 是一个自由软件项目 它是一种编译器基础设施 以 C 写成 包含一系列模块化的编译器组件和工具链 用来开发编译器前端和后端 它是为了任意一种编程语言而写成的程序 利用虚拟技术创造出编译时期 链接时期 运行时期以及 闲置时期 的最优化