iOS底层探索(二) - 写给小白看的Clang编译过程原理

iOS底层探索(一) - 从零开始认识Clang与LLVM

写在前面

编译器是属于底层知识,在日常开发中少有涉及,但在我的印象中,越接近底层是越需要编程基本功,也是越复杂的。但要想提升技术却始终绕不开要对底层原理的探究,很多资料都是直接抛出一堆函数概念和一顿操作,基础一般的小伙伴看了表示一脸懵逼。在此结合我自己的理解进行优化总结一下。毕竟知识水平有限,有问题或总结不妥的地方欢迎指出,多多学习,非常感谢!2018.2

入门起步

  • 经过上一篇对编译器的基本介绍,相信大家对Clang都有一个基本的认识了,通俗来说是一个编译器的前端,负责分析源代码(就是我们使用的C/OC/C++等)。

Clang的编译过程

1.预处理

  • 预处理顾名思义是预先处理,那预处理都做了哪些事情呢?内容如下。

  • (1) import 头文件替换

    • 面向对象编程的思维下,我们写代码会经常用到其他类的属性\方法等,我们只需要导入头文件就可以用了,如:

      #import <Foundation/Foundation.h> 
      // 这里将会在预处理时会把 Foundation.h 文件的内容拷贝过来并替换
      复制代码
    • 基于这个原理,这里引出了一个小问题,如果 ClassA.h 文件引用了 ClassB.h ,并且 ClassB.h 也引用了 ClassA.h ,这里是不是就会互相循环引入了?

      • 解决办法是在头文件中使用
      @class ClassA;
      复制代码
      • 代替
      #import "ClassA.h"
      复制代码
      • 这么写意思是声明 ClassA 是一个类,这样你就可以使用ClassA做类名了,如果需要使用 ClassA 的方法属性等可以在 .m 实现文件中再通过 import MyClass.h 的方式使用,这种方法不但可以解决互相引入的问题还可以优化编译速度。
  • (2) macro 宏展开

    • 无参宏: 如:

      #define DATA_TYPE_NUM @"number"
      复制代码

      在此宏定义作用域内,输入了 DATA_TYPE_NUM,在预处理过程中 DATA_TYPE_NUM 都会被替换成 @"number"。

    • 带参宏: 带参数的宏 如:

      #define CYXColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
      复制代码
  • (3) 处理其他的预编译指令(其实预编译过程也是出了预编译指令的过程)

    条件编译语句也是在预处理阶段完成,并且条件编译只允许编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率,如以下代码就只会保留一个return语句:

    #if DEBUG        return YES;
    #elsereturn NO;
    #endif
    复制代码
  • (4) 总结:

    • 简单来说,“#”这个符号是编译器预处理的标志, 以下是一些常用的预处理指令参考
    预处理指令用法解析
    #undef取消已定义的宏
    #if如果给定条件为真,则编译以下代码
    #ifdef如果宏已经定义,则编译以下代码
    #ifndef如果宏没有定义,则编译以下代码
    #elif如果前面的#if给定条件不为真,当前条件为真,则编译以下代码
    #endif结束一个#if……#else条件编译块
*PS:还需要了解更多关于预编译的内容,还请自行百度*
[图片上传失败...(image-cf6f6f-1531632712782)][图片上传失败...(image-fd9112-1531632712782)]`$clang -E main.m`
复制代码

2. Lexical Analysis - 词法分析(输出token流)

  • 预处理完成了以后,开始词法分析。词法分析其实是编译器开始工作真正意义上的第一个步骤,其所做的工作主要为将输入的代码转换为一系列符合特定语言的词法单元,这些词法单元类型包括了关键字,操作符,变量等等。举个例子:

Objective-C语言包含了关键字if、else、new等,那么在词法分析步骤时,遇到i与f或n与e与w组合在一起的时候,需要将这几个字母组合为关键字if或new这个词法单元。

  • 词法分析,只需要将源代码以字符文本的形式转化成Token流的形式,不涉及交验语义,不需要递归,是线性的。

    什么是token流呢?可以这么理解:就是有"类型",有"值"的一些小单元。

  • 再举个例子:

    比如一个运算表达式:(28 + 78) * 2 这里面只需要解析出(是一个开括号,28 是数字整形,+ 是一个运算符号即可。

编译指令: $clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

3.Semantic Analysis - 语法分析(输出(AST)抽象语法树)

编译指令:$clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

  • 语法分析的最终产物是输出抽象语法树

  • 语法分析,在Clang中由Parser和Sema两个模块配合完成

  • 交验语法是否正确

  • 根据当前语言的语法,生成语意节点,并将所有节点组合成抽象语法树(AST)

  • 这一步跟源码等价,可以反写出源码

  • Static Analysis 静态分析

    • 通过语法树进行代码静态分析,找出非语法性错误
    • 模拟代码执行路径,分析出control-flow graph(CFG) 【MRC时代会分析出引用计数的错误】
    • 预置了常用Checker(检查器)

未完待续 ...

这是上篇,为保证博客质量与阅读体验(个人感觉一次阅读过多文字有点影响阅读体验),先分享已完成的上半部分,下篇将继续介绍Clang编译过程中的剩下环节,欢迎持续关注,感谢理解与支持!2018.2

预告:下篇将继续介绍Clang与LLVM以下环节的相关知识。

下面是一些关键词,有兴趣的朋友先自行谷歌学习吧,下篇等我有闲情的时候再更新了,我也不知道什么时候。2018.7.15

4. CodeGen - (Intermediate Representation,简称IR)IR中间代码生成

  • CodeGen 负责将语法树丛顶至下遍历,翻译成LLVM IR
  • LLVM IR 是Frontend的输出,也是LLVM Backend的输入,前后端的桥接语言 (Swift也是转成这个)
  • 与 Objective-C Runtime 桥接
    • Class/Meta Class/Protocol/Category内存结构生成,并存放在指定section中(如Class:_DATA, _objc_classrefs)
    • Method/lvar/Property内存结构生成
    • 组成method_list/ivar_list/property_list并填入Class
    • Non-Fragile ABI:为每个Ivar合成OBJC_IVAR_$_偏移值常量
    • 存取Ivar的语句(ivar = 123; int a = ivar;)转写成base + OBJC_IVAR$_的形式
    • 将语法树中的ObjcMessageExpr翻译成相应版本的objc_msgSend,对super关键字的调用翻译成objc_msgSendSuper
    • 根据修饰符strong/weak/copy/atomic合成@property 自动实现的 setter/getter
    • 处理@synthesize
    • 生成block_layout的数据结构
    • 变量的capture(__block/__weak)
    • 生成_block_invoke函数
    • ARC:分析对象引用关系,将objc_storeStrong/objc_storeWeak等ARC代码插入
    • 将ObjCAutoreleasePoolStmt转译成objc_autoreleasePoolPush/Pop
    • 实现自动调用[super dealloc]
    • 为每个拥有ivar的Class合成.cxx_destructor方法来自动释放类的成员变量,代替MRC时代的“self.xxx = nil”

5. Optimize - 优化IR

  • 递归优化成伪递归

6. LLVM Bitcode - 生成字节码

7. Assemble - 生成Target相关汇编

  • Assemble - 生成Target相关Object(Mach-O)

8. Link生成Executable

参考文档

https://zh.wikipedia.org/wiki/C%E9%A2%84%E5%A4%84%E7%90%86%E5%99%A8 https://llvm.org/docs/tutorial/LangImpl2.html https://www.objc.io/issues/6-build-tools/compiler/

转载于:https://juejin.im/post/5b4af8b0e51d45199060fdf8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/277657.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、构建Node Web程序

---恢复内容开始--- 一、HTTP 服务器的基础知识 1、Node如何向开发者呈现HTTP请求 2、一个用“Hello World”做响应的HTTP服务器 它用了默 认的状态码200&#xff08;表明成功&#xff09;和默认的响应头 3、读取请求头及设定响应头 Node提供了几个修改HTTP响应头的方法&#x…

datagrid 什么时候结束编辑_2020年中考结束后,什么时候出分?什么时候报志愿?...

导语7月19日下午16:00&#xff0c;2020年北京中考正式落下帷幕。考试结束后&#xff0c;很多家长和考生都会长舒一口气&#xff0c;但北京中考在线团队提醒你&#xff0c;现在还不是放松的时刻&#xff0c;中考结束后&#xff0c;还有成绩查询和填报志愿等重要事件等着你。那么…

Unity3D学习笔记之七创建自己的游戏场景

到现在为止我们已经拥有了比较完备的Prefab&#xff0c;已经可以创建宏大的游戏场景&#xff0c;并以第一人称视角在场景中漫游了。这里给大家做个小的示范&#xff0c;建一个小场景大家在创建场景的时候需要自由发挥&#xff0c;做个尽量大的场景出来。这一系列教程以及素材均…

excel if in函数_【Excel函数】Small+Index+IF 一对N返回

通常情况下&#xff0c;Vlookup和lookup函数只能返回满足条件的第一个&#xff0c;剩余的都不会返回。 这也是其函数的一个弊端之一。 若是按照条件&#xff0c;返回所有满足条件的数据&#xff08;1->N&#xff09;的&#xff0c;可是适用组合函数。 Index返回位置&#xf…

Unity3D学习笔记之八为场景添加细节(一)

这一系列教程以及素材均参考自人人素材翻译组出品的翻译教程《Unity游戏引擎的基础入门视频教程》&#xff0c;下载链接附在第二篇学习笔记中。我花了30分钟做了一个中等大小的迷宫场景&#xff0c;不知道大家自己发挥&#xff0c;做的场景大小如何。在完成场景之后&#xff0c…

mysql数据库表的管理(增删改)

表字段管理1. 添加到末尾alter table 表名 add 字段名 数据类型;2 添加到开头alter table 表名 add 数据类型 first;3. 添加到指定位置alter table 表名 add 新字段名 数据类型 after 原有字段名&#xff1b;4. 删除字段alter table 表名 drop 字段名;5. 修改数据类型alter ta…

哪个app最费电_微波炉和烤箱,买哪个划算?

微波炉和烤箱不能说买哪个划算&#xff0c;而是看哪个更适合&#xff1f;我家微波炉和烤箱两个都有&#xff0c;所以这个问题我来回答一下。虽然外形上看起来&#xff0c;微波炉和烤箱似乎没有多大的区别&#xff0c;从功能上看&#xff0c;它们也都是加热&#xff0c;但它们侧…

MATLAB数值计算与符号运算

符号计算 存放的是精确数据&#xff0c;耗存储空间 &#xff0c;运行速度慢&#xff0c;但结果精度高&#xff1b; 数值计算则是以一定精度来计算的&#xff0c;计算结果有误差&#xff0c;但是运行速度快。转载于:https://www.cnblogs.com/shawnchou/p/10927680.html

Unity3D学习笔记之九为场景添加细节(二)

上节为场景中添加了第一块带有碰撞器的石头&#xff0c;本节我们来利用Prefab&#xff0c;将场景细节都添加进去&#xff0c;并且做的更完善。这一系列教程以及素材均参考自人人素材翻译组出品的翻译教程《Unity游戏引擎的基础入门视频教程》&#xff0c;下载链接附在第二篇学习…

vux Cell组件

Cell 组件一 <style lang"scss">.cell {padding-top: 15px;padding-bottom: 15px;color: #333;img {display: block;margin-right: 15px;}} </style><template><Group><cell class"cell" title"钱包" :border-intent…

wifi名称可以有空格吗_收购公司后可以变更公司名称吗,变更公司名称和股权如何处理?...

【点击文末小程序&#xff0c;免费咨询法律问题】公司收购是指二手设备收购&#xff0c;指向目标公司的二手设备&#xff0c;废旧物资&#xff0c;进而获取目标公司的全部或部分业务&#xff0c;取得对拆除的控制权。那么&#xff0c;收购公司后可以变更公司名称吗&#xff0c;…

震惊的网站,都是干货

分享15个鲜为人知的的小众网站&#xff0c;每一个可以让你打开新世界的大门&#xff0c;让你震惊。 1&#xff1a;仿知网 https://www.cn-ki.net/ 仿知网是一个完全可以代替知网的精品网站&#xff1b;是一个非常强大的论文搜索网站。 首先这个网站的论文检索结果和知网的搜索结…

Kinect开发笔记之二Kinect for Windows 2.0新特性

这是本博客的第一篇翻译文档&#xff0c;笔者已经苦逼的竭尽全力的在翻译了&#xff0c;但无奈英语水平也是很有限&#xff0c;不对或者不妥当不准确的地方必然会有&#xff0c;还恳请大家留言或者邮件我以批评指正&#xff0c;我会虚心接受。谢谢大家。 原文网址&#xff1a;h…

持久化的基于L2正则化和平均滑动模型的MNIST手写数字识别模型

持久化的基于L2正则化和平均滑动模型的MNIST手写数字识别模型 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献Tensorflow实战Google深度学习框架 实验平台: Tensorflow1.4.0 python3.5.0MNIST数据集将四个文件下载后放到当前目录下的MNIST_data文件夹下 定义模型框架与…

怎样制作滴滴截图_滴滴老了吗?

作者 / 薛静 来源 / 盒饭财经(ID&#xff1a;daxiongfan)滴滴最近有点忙。6月11日&#xff0c;滴滴地图与公交事业部负责人柴华还在忙于解答消费者对于滴滴司机绕路的质疑&#xff0c;网上就流传出了滴滴司机直播性侵的消息。当晚&#xff0c;滴滴急忙在官方微博中做出回应称已…

mysql Backup recovery

如果您要在MySQL数据库中存储任何您不想丢失的内容&#xff0c;那么定期备份数据以保护数据免受损失非常重要。本教程将向您展示两种简单的方法来备份和恢复MySQL数据库中的数据。您还可以使用此过程将数据移动到新的Web服务器。 从命令行备份&#xff08;使用mysqldump&#x…

Kinect开发笔记之三Kinect开发环境配置详解

0、前言&#xff1a;首先说一下我的开发环境&#xff0c;Visual Studio是2013的&#xff0c;系统是win8的64位版本&#xff0c;SDK是Kinect for windows SDK 1.8版本。虽然前一篇博文费了半天劲&#xff0c;翻译了2.0SDK的新特性&#xff0c;但我还是决定要回退一个版本。其实我…

opencv python 图像缩放/图像平移/图像旋转/仿射变换/透视变换

Geometric Transformations of Images 1图像转换 OpenCV提供了两个转换函数cv2.warpAffine和cv2.warpPerspective&#xff0c;可以使用它们进行各种转换。 cv2.warpAffine采用2x3变换矩阵&#xff0c;而cv2.warpPerspective采用3x3变换矩阵作为输入。 2图像缩放 缩放只是调整图…

.net调用c++方法时如何释放c++中分配的内存_C/C++编程笔记:C语言编程知识要点总结!大一C语言知识点(全)...

一、C语言程序的构成与C、Java相比&#xff0c;C语言其实很简单&#xff0c;但却非常重要。因为它是C、Java的基础。不把C语言基础打扎实&#xff0c;很难成为程序员高手。1、C语言的结构先通过一个简单的例子&#xff0c;把C语言的基础打牢。C语言的结构要掌握以下几点&#x…

Django 使用 mysql 数据库连接

启用 mysql 数据库连接 修改 app01 下的 __init__.py import pymysqlpymysql.install_as_MySQLdb() 修改 settings.py DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: django,USER: django,PASSWORD: django,HOST: 192.168.0.200,PORT: 3306,} } 测试 #生成同步…