【学习总结】05 | 链接器:符号是怎么绑定到地址上的?

1,134

1、前言

首先,我认为学习总结,要有所总,所结,就是有归纳后,能用自己的话告诉别人!有所结,就是有所收获输出,一般我认为是思维导图,所以,每篇文章前,我都会先给出文章的脑图:

iOS开发高手课-05-链接器:符号是怎么绑定到地址上的?.png

2、正文

注意,本系列总结不会引用或提供原课程文章所有的内容或代码,只会作出思维导图,需要学习可购买课程 《iOS开发高手课 - 极客时间》

链接器 对于刚刚接触程序开发的同学可能基本不懂,虽然大学学习编译原理计算机原理等。这些知识比较抽象,为了让大家明白,我们需要站在巨人的肩膀上!所以,本文需要一个巨人 ----- 编译器 来帮助大家理解 链接器 是什么?为什么?大家有没有想过,你写的代码,最终是怎么样在计算机或手机上运行的???那现在就让我们来了解一下吧!

《程序是怎样跑起来的》

“计算机组成原理”图解趣味版,蹲马桶就能看懂的编程基础知识!普及计算机知识。如何向小学生讲解CPU和二进制?如何向中学生讲解内存和磁盘?如何向女高中生讲解操作系统的原理?如何向老奶奶说明显示器和电视的不同?

《程序是怎样跑起来的》作者是日本矢泽久雄,我们需要解析 编译器,所以需要简单入门级的计算机组成原理,这本书就是这样一本优秀的书!大家可能通过微信读书读到电子版: 程序是怎样跑起来的 - 微信读书,目前2020年微信还有很多无限卡会员的免费阅读,当然如果必要花 19.99 元我认为也值得。好了我们就不多说了,下面我主要摘取书中几个示意图来解析 编译器

程序运行流程示例

图1-1-程序运行流程示例.jpg

上图展示程序运行流程示例,从我们编写的高级语言的代码,到 CPU(Central Processing Unit,中央处理器)所负责的就是解释和运行最终转换成机器语言的程序内容,其实是 编译器 工作的流程。

CPU的四个构成部分

图1-2-CPU的四个构成部分.jpg

CPU 的内部由寄存器控制器运算器时钟四个部分构成,各部分之间由电流信号相互连通。本文我们不关注 CPU 的工作原理,本图主要是后面要解析代码运行在不同 CPU 上,需要 编译器 对不同的 CPU 做兼容和优化。为什么会有不同的 CPU,上图就说明了,简单来说寄存器、控制器、运算器和时钟的设计和数量不同,那就是不同的 CPU,所以代码在不同的 CPU 运行就可能有不一样的要求,这是硬件方面。这里就不深入解析了,大家可以看看本书,或自行搜索了解更多。

CPU负责解析并运行从源代码编译而来的本地代码

图7-2-CPU负责解析并运行从源代码编译而来的本地代码.jpg

CPU 只能解释其自身固有的机器语言,机器语言的程序称为本地代码(native code)。不同的CPU能解释的机器语言的种类也是不同的。例如,CPU有 x86MIPSSPARCPowerPCARM等几种类型,它们各自的机器语言是完全不同的。

程序员用C语言等编写的程序,在编写阶段仅仅是文本文件,文本文件(排除文字编码的问题)在任何环境下都能显示和编辑,我们称之为源代码。通过对源代码进行编译,就可以得到本地代码。到目前,我们了解了代码编译的流程啦,那具体的流程又是怎么样的呢?在讲解之前,我们先看看 CPU 的历史,这样对我们了解编译器也起到重要作用啊~

这里解析一下各种 CPU :

  • x86:美国 Intel (英特尔)的微处理器,是按照8086、80286、80386、80486、Pentium(奔腾)……这样的顺序不断升级的。因为这些型号的后面都带有86,所以总称为x86。32位处理器 Intel官方文档里面称为“IA-32”,64位处理器称“x86_64”、“x86-64”,又称x64,即英文词 64-bit extended,64位拓展的简写。这个64位有点故事,下面讲。现在的PC机都是64位 CPU 啦。
  • MIPS:美国 MIPS 科技公司开发的CPU,曾出现过面向 MIPS工作站的 Windows,不过现在市面上已经不再出售了。
  • SPARC:美国 SUN系统开发的CPU,很多工作站都采用了该CPU。
  • PowerPC:是美国苹果、IBM、摩托罗拉共同开发的CPU,苹果的Power Mac及IBM的工作站都采用了该CPU,不过现在的Mac采用的是Intel的x86系列CPU。
  • ARM ARM,安谋控股公司(英语:ARM Holdings plc.),又称ARM公司。ARM的前身为艾康电脑,1978年于英国剑桥创立。2016年7月18日,日本软银集团斥资3.3万亿日元(约合311亿美元)收购了ARM公司。ARM架构版本从 ARMv3 到 ARMv7 支持32位,2011年发布的ARMv8-A 架构添加了对64位支持。现在移动设备主流就是使用 ARM 。
x86-64 的故事

x84_64x86 32位 CPU 开始迈向64位的时候,有2种选择:

  1. 向下兼容x86。
  2. 完全重新设计指令集,不兼容x86。

结果在 1999 年 AMD 抢跑了!比 Intel 率先制造出了商用的兼容 x86 的CPU,AMD称之为 AMD64,抢了64位PC的第一桶金,得到了用户的认同。所以 Intel 为了面子就选择了设计一种不兼容x86的全新64为指令集,称之为IA-64(Itanium,安腾),但是比 AMD 晚了一步,因为 AMD64 能有效地把x86架构移至64位的环境,并且能兼容原有的x86应用程序。并且 IA-64 也挺惨淡的,因为是全新设计的CPU,没有编译器,也不支持 Windows(微软把intel给忽悠了,承诺了会出对应的 Windows server 版,但是迟迟拿不出东西),处理器本身和软件移植的成本难以控制,导致 IA-64 最终流产。后来不得不在时机落后的情况下也开始支持AMD64的指令集,但是换了个名字,叫x86_64,表示是 x86 指令集的64扩展,大概是不愿意承认这玩意是AMD设计出来的?现时英特尔称之为“Intel 64”,在之前曾使用过“Clackamas Technology” (CT)、“IA-32e”及“EM64T”等名字。换汤不换药,核心与 AMD64 几乎相同,犹如一对孪生兄弟,其实都是 x86-64 架构。当年有媒体为 EM64T 起了“iAMD64”别名,讽刺 Intel 在迎击 AMD 的民用64位技术上,使用了 AMD 的技术,直接把 AMD64 吸纳过来,并以新名重新包装使用,所以最后,Intel 索性将此技术正式命名为 Intel 64

所以,CPU 的 32 位还是 64位,一般是用 x86-64 表示64位,而32位现在已经没有了。另外,不同公司对 x86-64 架构,名字上还是有一些区别,苹果公司和RPM包管理员以“x86-64”或“x86_64”称呼此64位架构。甲骨文公司及Microsoft称之为“x64”,BSD家族及其他Linux发行版则使用“x64-64”,32位版本则称为“i386”(或 i486/586/686),Arch Linux用x86_64称呼此64位架构。

最后一个问题,x86、x86_64主要的区别是什么?就是32位和64位的问题,x86 中只有8个32位通用寄存器,分别是 eax,ebx,ecx,edx, ebp, esp, esi, edi。x86_64 把这8个通用寄存器扩展成了64位的,并且比x86增加了若干个寄存器(好像增加了8个,变成了总共16个通用寄存器)。譬如四个通用寄存器(RAX, RBX, RCX, RDX)是由32位的(EAX, EBX, ECX, EDX)64位扩展而来,相应的还有指针寄存器(RIP, RBP, RSP, RSI, RDI),以及增加八个通用寄存器(R8~R15)等等。 这些资源只可在x64处理器的64位模式下使用,在用来支持x86软件的遗留模式和兼容模式中是不可见的。

以上内容和关于 CPU 更多历史和资料,可查看来源: x86 - 维基百科x86-64 - 维基百科,自由的百科全书X86、X64和X86_64区别

转换成本地代码后就变成了同样的语言

图8-2-转换成本地代码后就变成了同样的语言.jpg

前面提到,CPU 只能解释其自身固有的机器语言,而转换成机器语言的程序就是本地代码。不管用那种编程语言编写的源代码,最后只要能翻译(编译)成本地代码,那么 CPU 就能理解。这个过程,其实就是编译器的工作内容!

同样的源代码可以转换成适用于不同处理器的本地代码

图8-5-同样的源代码可以转换成适用于不同处理器的本地代码.jpg

根据 CPU 类型的不同,本地代码的类型也不同。因而,编译器不仅和编程语言的种类有关,和 CPU 的类型也是相关的。这就是前面为什么要重点说 CPU 相关知识,现在是不是有点理解编译器了!

把C语言等高级编程语言编写的源代码转换本地代码的程序称为编译器,这个转换过程经过语法解析、句法解析、语义解析等。每种编程语言编写的源代码都需要其专用的编译器,或者是同用类编译器,比如 C 家族(C/C++)的编辑器。

Windows中的编译和链接机制

图8-8-Windows中的编译和链接机制.jpg

刚才说的高级编程语言的源代码转换本地代码,本地文件是无法直接运行的,还需要把多个目标文件结合,生成1个可执行文件(图中是EXE文件,针对Windows系统的。),这个处理就是链接,运行连接的程序就称为链接器(linkage editor,或连结器)。至此,我们终于说到链接器啦!!!现在明白链接器是在那里使用了吧?

存储着目标文件的实体,并直接和可执行文件结合的库文件形式称为静态链接库,经常简称为静态库。与之相反的,就叫动态链接库(动态库),就是参与链接过程,但是并不会与可执行文件结合,就是说链接时会做标记,绑定的地址在加载后再决定。这个不理解,没关系,下面还会在详细说说,下一章的内容就是动态链接库动态链接器的内容,所以,这个需要了解一下。

至此,我们就过编译器相关的内容,简单的解说了一下,不知道大家有点理解没有,下面,我们在深入一点,了解编译器的具体工作流程。

编译器

编译器一般采用 Three-Phase(三阶段/三相)架构设计:

  1. 编译器前端(Front end)
  2. 中间端(Middle end,或叫优化器,Optimizer)
  3. 后端(Backend)

编译器前端(Front end)

  1. Preprocess - 预处理
  2. Parser - 解析器
  3. Lexical Analysis - 词法分析
  4. Semantic Analysis - 语义分析
  5. AST(Abstract Syntax Tree,抽象语法树)
  6. Static Analysis - 静态分析
  7. CodeGen - IR 代码生成

编译器前端的任务:预处理语法分析语义分析,在这个过程中,也会进行类型检查,如果发现错误或者警告会标注出来在哪一行等,最终生成中间代码 IR(Intermediate Representation,中间端表达式)。对于 LLVM 来说,前端就是 CLang

中间端(Middle end,或叫优化器,Optimizer)

  1. LLVM Bitcode - 生成字节码
  2. Assemble - 生成Target相关汇编
  3. Assemble - 生成Target相关 Object(Mach-o)
  4. Link 生成 Executable 可执行文件

优化是非常重要的,很多直接转换来的代码是不合适且消耗内存的,因为是直接转换,所以必然会有这样的问题,而优化放在这一步的好处在于前端不需要考虑任何优化过程,减少了前端的开发工作。中间代码要经过一系列的优化,优化用的是 Pass,中间代码的优化也可以开发者自己编写,可以插入一个 Pass

后端(Backend)

  • ARM(ARM,安谋控股公司)
  • x86|x86-64(Intel,英特尔)
  • PowerPC(Apple & IBM & Motorola,AIM联盟)

编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。对于 iOS 的编译过程,后端的处理:LLVM优化器会进行BitCode的生成,链接期优化等,LLVM机器码生成器会针对不同的架构,比如arm64等生成不同的机器码。

这里的后端,最终就是生成对应的 CPU 能执行的机器语言,前面已经介绍过 CPU 相关的。

上面说了编译器的组成架构和简要的工作流程,详细的工作流程这里就不多说了,因为已经有很多优秀的内容了,并且本文的主要目的是要说明编译器是什么!你知道它是什么后,再了解它是怎么用,有什么优缺点,自然不是难事!以上的部分内容是针对 iOS 和 LLVM 的,所以,我们接下来就来介绍一下 LLVM 编译器吧!

要讲解 LLVM 前,有必要的说说 GCC(GNU Compiler Collection,GNU编译器套件) ,因为苹果最初也是使用 GCC,后来慢慢的替换为 LLVM 的。

GCC(GNU Compiler Collection,GNU编译器套件)

原名:GNU C语言编译器(GNU C Compiler),通常是跨平台软件的编译器首选。(在所有平台上都使用同一个前端处理程序,产生一样的中间码)。

但是由于以下问题,导致苹果转为 LLVM:

  • GCC 的 Objective-C Frontend 不给力
  • GCC 插件、工具、IDE的支持薄弱

GCC的前端不是苹果提供维护的,想要添加一些语法提示等功能还得去求GCC的前端去做。 很多编译器特性没有,自动补全、代码提示、warning、静态分析等这些流程不是很给力,都是需要IDE调用底层命令完成的,结果需要以插件的形式暴露出来,这一块GCC做的不是很好。

LLVM

早年Apple一直使用 GCC 作为官方的编译器,但Apple对 GCC 的性能不满意,再者 Objective-C 在 GCC 中优先级低,GCC 对 Objective-C 语言新特性的支持程度也不高。因此Apple一直在寻找compiler(编译器)的开源替代品,于是他们将目光转移到LLVM身上。

来自维基百科:关于LLVM这个名字的来源,LLVM的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,由于这个项目的范围并不局限于创建一个虚拟机,这个缩写导致了广泛的疑惑。

LLVM 就是 LLVM, 并不是 Low Level Virtual Machine(底层虚拟机)的简写!现今LLVM 已单纯成为一个品牌!根据官网说明:

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. Despite its name, LLVM has little to do with traditional virtual machines. The name "LLVM" itself is not an acronym; it is the full name of the project. LLVM项目是模块化和可重用的编译器及工具链技术的集合。尽管名称如此,LLVM与传统虚拟机关系不大。名称“ LLVM”本身不是缩写。它是项目的全名。

2000年,伊利诺伊大学厄巴纳-香槟分校(University of Illinois at Urbana-Champaign 简称UIUC)这所享有世界声望的一流公立研究型大学的 Chris Lattner(克里斯·拉特纳,twitter @clattner_llvm ) 和 Vikram Adve(维克拉姆·艾夫)想要为所有静态及动态语言创造出动态的编译技术,而开发的编译器开发工具套件。2005年,苹果电脑雇用了 Chris Lattner 克里斯·拉特纳及他的团队为苹果电脑开发应用程序系统,LLVM 涉及范围越来越大,可以用于常规编译器,JIT编译器,汇编器,调试器,静态分析工具等一系列跟编程语言相关的工作。Chris Lattner 后来又开发了 Clang,使得 LLVM 直接挑战 GCC 的地位。

Chris Lattner 大神简介

Chris Lattner 生于 1978 年,2005年加入苹果,将苹果使用的 GCC 全面转为 LLVM。2010年开始主导开发 Swift 语言。2017年1月,克里斯·拉特纳 辞去在苹果的工作,入职特斯拉汽车,负责自动驾驶软件的开发。2017年8月14日,克里斯·拉特纳 发表Twitter表示将于一周后加入聚焦于深度学习与人工智能研发的Google Brain团队。

Xcode 历史

Clang 编译效率是 GCC 的3倍,编译器性能好,编译出的文件小。LLVM 3.0 发布已完整支持所有 ISO C++ 标准,代表着 LLVM 正式走向成熟。所以,也标志着 Xcode 的变化。

  • Xcode3:GCC前端-LLVM后端,
  • Xcode4.2:Clang-LLVM 3.0 成为默认编译器,
  • Xcode5: GCC 被废弃,新的编译器是 LLVM 5.0

从 GCC前端 到 LLVM后端的编译器,到 Clang-LLVM 的编译器,一步步收回对编译工具链的控制,也为 Swift 的出现奠定基础。所以,Chris Lattner 真的是大神!

当前 Xcode11 对应:

Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

查看你当前使用的 LLVM 可以用命令:llvm-gcc -v

LLVM 工具链

LLVM工具链集合.png

最后用这张图来表示完整的LLVM工具链集合的六大执行单元。

  1. 词法分析: 将源代码中的所有字符切分成记号(Token)的序列。包括了词法分析器、记号序列化生成器和扫描器,不过扫描器常常作为词法分析器的第一阶段。
  2. 语法分析: 分析符合一定语法规则的一串符号,它通常会生成一个抽象语法树(AST - Abstract Syntax tree),用于表示记号之间的语法关系。
  3. 语义分析: 通过语法分析的解析后,这个过程将从源代码中收集必要的语义信息,通常包括类型检查、在使用之前确保声明了变量等等。
  4. 中间代码(IR)生成:代码在这个阶段会转换为中间表示式(IR),这是一种中立的语言,与源语言(前端)和机器(后端)无关。
  5. 优化中间表达式:中间代码常常会有冗余和死代码的情况出现,而优化器可以处理这些问题以获得更优异的性能。
  6. 生成目标代码: 最后后端会生成在目标机器上运行的机器码,我们也将其称之为目标代码。

链接器

  • 为什么要让链接器做符号和地址绑定?不绑定的话,又会有什么问题?
  • 链接器为什么还要把项目中的多个 Mach-O 文件合并成一个。

回到本文开始的问题,大家对这2个问题心中有答案了吗?

链接器的作用是将符号绑定到地址上,符号表是内存地址与函数名、文件名、行号的映射表。所以,变量、函数与地址绑定,CPU 才能理解解析代码。而为什么要多个 Mach-O 文件合并一个最终的 Mach-O?过去面向过程编程时,可以写一个文件中,而现在主流是面向对象,就有类与对象关系,所以一般是分类、分模块、分空间来编写源代码,所以,需要把这些类与对象和他们之前调用关系绑定一起,合并成一个Mach-O。为了更好理解这个 Mach-O,需要了解 CPU 是怎么执行他们的,这里就不展开了,感兴趣的同学可以先自行搜索了解更多。

触类旁通

Clang/Swift-LLVM编译器架构.png

让我们再次回顾一下编译器的工作流程,以 LLVM 为例,从 iOS 开发视角来看这个问题。这张图片来源:从Swift桥接文件到Clang-LLVM - 掘金。详细的编译器过程大家可以参考文章,这里就不过多重复。

Clang-LLVM编译过程.png

另外,原文还提到很多的概念,这里也不一一提出了,具体可以看看本文最前面的思维导图。比如:

  • AST(Abstract Syntax Tree,抽象语法树)
  • Mach-O:是 Mach Object 文件格式的缩写,它是一种用于可执行文件,目标代码,动态库,内核转储的文件格式。作为a.out格式的替代,Mach-O提供了更强的扩展性,并提升了符号表中信息的访问速度。
  • 符号表:是内存地址与函数名、文件名、行号的映射表。格式如:<起始地址> <结束地址> <函数> [<文件名:行号>]
  • dyld(the dynamic link editor):当加载 Mach-O 文件时,动态链接器会先检查是否有共享缓存。每个进程都会在自己的地址空间映射这些共享缓存,这样做可以起到优化App启动速度的作用。
  • LLDB(LLVM项目的调试器组件)
  • ASLR (Address space layout randomization,地址空间配置随机加载)
  • 解释器:不需要经过编译的过程,而是在执行的时候通过一个中间的解释器将代码解释为CPU可以执行的代码。JavaScript、Python、PHP等都是直译式语言。
  • Bitcode:字节码
  • SIL(Swift Intermediate Language):AST 和LLVM IR之间的另一种中间代码表示形式。主要是用来弥补一些 Clang编译器的缺陷,如无法执行一些高级分析,可靠的诊断和优化等。

中间代码 LLVM IR

中间端表达式 IR(Intermediate Representation),有3种表示形式,但本质是等价的,就好比水可以有气体,液体,固体3种形式。

  1. text:便于阅读的文本格式,类似于汇编语言,拓展名.II。生成命令:$ clang -S -emit-llvm main.m
  2. memory:内存格式,开发时操作 LLVM IR。
  3. bitcode:二进制格式,拓展名.bc。生成命令:$ clang -c -emit-llvm main.m

广义与狭义 LLVM 与 Clang 的关系

广义 LLVM:整个 LLVM 架构。

狭义 LLVM:LLVM 后端(代码优化,目标文件生成等。)

Clang(C Lange Family Frontend for LLVM),发音为/ˈklæŋ/,是C、C++、Objective-C、Objective-C++ 编程语言的编译器前端。

所以,非特指,LLVM 就是广义 LLVM,指整个LLVM项目,包括Clang前端。另外,本文主要讲解了 LLVM 在 Apple 平台上的使用,LLVM 现在被作为实现各种静态和运行时编译语言的通用基础结构,可以使用 LLVM 来编译Ruby,Python,Haskell,Java,D,PHP,Pure,Lua和许多其他语言。LLVM 的主要优势在于其多功能性,灵活性和可重用性,这就是它被用于各种不同任务的原因:从轻量级JIT编译嵌入式语言(如Lua)到编译Fortran代码(用于大型超级)电脑。

相比较GCC,Clang具有哪些优点

  • Clang是:
  • LLVM项目的一个子项目
  • 基于LLVM架构的 C、C++、Objective-C、Objective-C++ 编译器前端
  • Clang优点:
  • 编译速度快:在某些平台上,Clang的编译速度显著的快过GCC
  • 占用内存小:Clang生成的AST(语法树)所占用的内存是GCC的五分之一左右
  • 模块化设计:Clang采用基于库的模块化设计,易于IDE集成及其他用途的重用
  • 诊断信息可读性强:在编译过程中,Clang创建并保存了大量详细的元数据,有利于调试
  • 设计清晰简单,容易理解,易于扩展增强

Swift 如何桥接 Objtive-C 文件到 Clang-LLVM ?

在 Swift 的项目中,Objtive-C 代码可以生成 IR(Intermediate Representation,中间端表达式),从而与 Swift 生成的 IR 联通。这个也是分段(层)的好处,编译器中间端(Middle end,或叫优化器,Optimizer),作为中间者通过前端获取 IR ,从而不用关心前端的编程语言是什么,这些设计特点,带来了非常大的好处。

假如有N种语言(C、OC、C++、Swift...)的前端,同时也有M个架构(模拟器、arm64、x86...)的Target,是否就需要 N × M 个编译器? 三相架构的价值就体现出来了,通过共享优化器的中转,很好的解决了这个问题。 假如你需要增加一种语言,只需要增加一种前端;假如你需要增加一种处理器架构,也只需要增加一种后端,而其他的地方都不需要改动。这复用思想很牛逼吧。

来自:浅谈iOS编译过程 - 简书

需要注意的是 Clang 是基于LLVM架构的 C、C++、Objective-C、Objective-C++ 编译器前端,不包括 Swift!苹果针对 Swift 做了单独的前端,与 Clang 是非常相似的,特点就是增加了 SILSwift Intermediate Language)。详细具体可以查看 WWDC 视频:What's New in LLVM - WWDC 2016 - Videos - Apple DeveloperBehind the Scenes of the Xcode Build Process - WWDC 2018 - Videos - Apple Developer

方舟编译器

方舟编译器架构示意图.png

当前方舟编译器支持Java/Kotlin程序字节码的前端输入,其它编程语言的支持(如 C/C++/JS 等)还在规划中,方舟编译器的中间表示(IR)转换器将前端输入转换成方舟IR,并输送给后端的优化器,最终生成二进制文件,二进制文件与编译器运行时库文件链接生成可执行文件,在方舟的运行环境中就可执行该文件。

方舟编译器IR是支持程序编译和运行的中间程序表示。程序源代码中的任何信息对于程序分析和优化都是有帮助的,所以方舟IR的目标是尽可能完整详细地提供源程序的信息。

方舟编译器开源范围示意图.png

首次开源范围是编译器 IR( Intermediate Representation)、RC(Reference Counting)和多语言设计思想等,用于与业界、学术界沟通交流。后续将陆续开源编译器前端、后端,支持其它语言(如 JavaScript)的编译等,当前部分Java语言特性和JVM虚拟机特性的支持未包括在本次开源代码中,包括:annotation、lambda表达式、泛型等。目前仍有很多地方不完善,会在社区陆续迭代,遇到问题请在社区提交 issue,欢迎在社区继续讨论设计和代码共建。

怎么样!现在你至少看的懂这个方舟编译器架构的大体流程了吧,是不是发现其实并没有那么难理解!那就对了,万事开头难,慢慢的一切都会简单起来~ 至少去知x上看看这些评论都看懂了啊,如何看待方舟编译器于 2019 年 8 月 31 日开源? - 知乎,是不是很开心~

详细可见官方网页:方舟编译器 OpenArkCompiler - FAQ

龙书、虎书、鲸书 --- 编译原理三大圣书

  1. 龙书:《编译原理》(编译原理 技术与工具)(Compilers: Principles,Techniques, and Tools)
  2. 虎书:《现代编译原理 — C语言描述》(Modern Compiler Implement in C)
  3. 鲸书:《高级编译器设计与实现》(Advanced Compiler Design and Implementation)

龙书:《编译原理》是编译领域无可替代的经典著作,因为书籍的封面是一条龙,所以被广大计算机专业人士誉为“龙书”。

虎书:增加了数据流分析、循环优化、内存管理等内容。

鲸书:包含了一些更比较高级的编译器的设计和实现。

大家是不是瞬间感觉自己就要买这几本书呢!!!我到底能不能看的懂呢?可以先自测一下自己是不是适配现在就学习编译原理:

学习编译原理前自测
  • a. 编译型语言和解释型语言的区别是什么?
  • b. 编译经历了哪几个基本过程? 每个过程主要干了什么事情?
  • c. 详细描述一下你最熟悉的语言中,赋值号的左边可以由哪些部分组成? 右边可以由哪些部分组成?
  • d. 什么是递归? 如何终止一个递归行为?
  • e. 什么是贪心过程?
  • f. 听说过 KMP 吗? 介绍一下它的基本思想.
  • g. 生成树是什么?
  • h. 你觉得编程语言和自然语言最重要的区别有哪些?
  • i. 什么是有限状态自动机? 你知道几种不同的自动机类型? 它们之间的区别和联系?
  • j. 内存被人为的划分成了哪几种不同的类型, 它们之间的区别和联系?
  • k. 什么是中断? CPU 在响应中断时会做什么事情?
  • l. 你最熟悉的语言有垃圾回收机制吗? 若有描述它进行垃圾回收的原理, 若没有则描述你在编写程序时是如何管理内存的?

本节内容来自:如何学习编译原理? - 欧长坤的回答 - 知乎

3、总结

终于到总结部分啦!这个文章,之前给我们组内同学分享时,在回顾都忘记了一大部分,另外在写成文字时,发现有很多东西需要考证,每篇文章花了很多心思,正好2020年新型肺炎冠状病毒都在家里,正好有这时间。而 维基百科 就是一个很棒的网站,关于大多数知识和历史都能查到,真的很有趣!

关于编译器的知识有太多了,深入的还可以自己写一个编译器!这里就达不到这样的层次,所以就提一下,有需要的同学可以自行搜索。关于LLVM的知识也还有很多没有讲到,比如抽象语法树(AST),前端 Clang 是重中之器,Clang 插件开发等,还有中间端的 Pass,后端的Mach-O 和 CPU 执行 Mach-O 的过程等。

最后,本文还是有很多细节无法用文字记录下来,大家可以阅读下面的参考链接,这样收获会更大。关于编译器链接器就到这里先,对于大家理解这个概念应该是没有问题啦!具体的实现细节,需要大家多学习,如果有能力,可以看看龙书!虎书!鲸书! 想想也是一件快乐的事件!

2020年,手机只是小小一部分,智慧家居大屏、穿戴、车机、音响、手表、PC等等各种各样设备,作为开发者,我们不要只关注自己开发的App,编译器知识是所有设备的基础,应该去理解这个世界发生什么变化,为什么变化,怎么变化,抓住变化!当然我承认世界是掌握于小数人,但能先抓住自己!这就是好的开始~


注:更多关于 iOS 开发和程序开发相关的内容,可以查看系列,目前还在连载中 【学习总结】iOS开发高手课 -- (连载中) | iHTCboy's blog,以上,希望对你有用!

参考

WWDC

Article


  • 如有侵权,联系必删!
  • 如有不正确的地方,欢迎指导!
  • 如有疑问,欢迎在评论区一起讨论!

注:本文首发于 iHTCboy's blog,如若转载,请注来源