美文网首页iOS开发指南
Clang探究及应用

Clang探究及应用

作者: 格雷s | 来源:发表于2020-05-21 11:43 被阅读0次

    1.前言

    本篇文章旨在展示Clang的探究过程

    • 探究Clang的意义
    • Clang在iOS当中的发展史
    • 编译过程
    • 学习Clang的实际应用

    2.意义

    • 1.oc、swift都是编译型语言,两者都采用Clang作为前端编译器,LLVM作为后端编译器,学习Clang了解程序的编译执行过程
    • 2.探究代码的底层实现
    • 3.了解mach-o,dylid,dSYM是什么
    • 4.app瘦身、启动优化、lldb调试技巧、Clang插件定制
      在学习戴铭的课程中也多次提到了Clang对于开发的帮助,有兴趣的可以去学习下iOS高手开发课

    3.Xcode中的编译器发展史

    • 1.xcode3以前:GCC
    • 2.xcode3:增加llvm,gcc前端+llvm后端
    • 3.xcode4.2:出现clang-llvm3.0成为默认编译器
    • 4.xcode4.6llvm升级到4.2版本
    • 5.code5:gcc被废弃,新的编译器是llvm5.0,从gcc过渡到clang-llvm时代
      参考指令:clang -v

    4.编译过程

    一次完整的编译流程:clang -ccc-print-phases main.m

    0: input, "main.m", objective-c         
    1: preprocessor, {0}, objective-c-cpp-output    
    2: compiler, {1}, ir
    3: backend, {2}, assembler
    4: assembler, {3}, object
    5: linker, {4}, image
    6: bind-arch, "x86_64", {5}, image
    

    4.1预处理

    xcrun clang -x objective-c -E -DDEBUG=1 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.m
    

    在xocde中查看preprocess过程Product->Perform Action->Preprocess

    4.2词法分析

    clang -fmodules -fsyntax-only -Xclang -dump-tokens -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.m
    

    4.3语法分析

    clang -fmodules -fsyntax-only -Xclang -ast-dump -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.m   
    

    4.4生成中间代码

    clang -O3 -S -fobjc-arc -emit-llvm -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.m -o main.ll
    

    O3代码优化级别,optimization level

    4.5生成目标文件

    clang -fmodules -c -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.m -o main.o
    
    

    4.6生成可执行文件

    clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk main.o AppDelegate.o -o main   
    

    4.7Demo演示

    新建一个C项目Demo ,演示生成可执行文件的过程


    image.png
    clang -fmodules -c main.c -o main.o
    clang main.o -o main
    ./main
    

    4.8Xcode查看编译过程

    我们可以查看到编译的整个过程信息


    image.png

    5.查看oc的c++实现

    clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk AppDelegate.m
    
    

    6.Mach-O

    编译后的可执行文件,包括exec(刚才生成的main)、dylib(/usr/lib)
    

    Mach-O 文件包含三个区域
    1.Mach-O Header:包含字节顺序,magic,cpu 类型,加载指令的数量等
    2.Load Commands:包含很多内容的表,包括区域的位置,符号表,动态符号表等。每个加载指令包含一个元信息,比如指令类型,名称,在二进制中的位置等
    3.Section:最大的部分,包含了代码,数据,比如符号表,动态符号表等。
    辅助查看工具MachoView

    image.png

    7.LinkMap文件

    Write Link Map File设置为YES,指定存储目录$(SRCROOT)/build/LinkMap.txt,编译后该文件列出了编译后的每一个.o文件(包括静态库里的),以及每一个每一个目标文件的代码段,数据存储详情.默认:Build/Intermediates.noindex/ClangDemo.build/Debug-iphonesimulator/ClangDemo.build
    __text表示编译后的程序执行语句,__data表示已初始化的全局变量和局部静态变量,__bss表示未初始化的全局变量和局部静态变量,__cstring表示代码里的字符串常量,等等。

    Address           Size      File    Name
    0x100001380   0x00000040  [  2]     +[ViewController createSark]
    偏移地址          4*16byte  所属文件
    

    8.学习Clang作用

    8.1App瘦身方案

    1.滴滴 基于clang插件的一种iOS包大小瘦身方案
    https://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247488360&idx=1&sn=94fba30a87d0f9bc0b9ff94d3fed3386&source=41#wechat_redirect
    2.微信 iOS微信安装包瘦身
    https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207986417&idx=1&sn=77ea7d8e4f8ab7b59111e78c86ccfe66&3rd=MzA3MDU4NTYzMw==&scene=6#rd
    3.阿里 减小ipa体积之删除frameWork中无用mach-O文件
    https://www.oschina.net/question/2625381_2168321

    可以看到以上方案都是基于编译过程/结果进行优化,可见Clang在app开发过程中起到的强大作用

    8.2App启动优化

    启动流程:
        1.Load dylibs->rebase->bind->objc->initializers
    读取app的可执行文件,Mach-o,在可执行文件的Mach_header查找lc_load_dylib的加载指令,查找需要的动态库dylib,
        2.加载到内存的可执行文件都是不可用的,需要ASLR(进程每次启动,地址空间都会被简单的随机化,有PIE标识,otool -hv ClangDemo),需要rabase,binding
            rebase:因为初始地址和内存地址不同,需要修正
            binding:因为动态库不编译进程序最终的二进制文件中,而是在运行的时候动态的查找调用函数的地址
        以上主要是__DATA中的指针数量
        3.objc setup        
        libsystem中libsystem_initializer初始化libdispatch,调用了os_object_init,最终调用了objc_init,objc_init中绑定了3个方法,map_2_images,load_images,unmap_images:
        map_2_images:Binding操作结束之后,发出dyld_image_state_bound通知,调用map_2_images,主要做以下几件事来完成objc setup:
        读取二进制文件的DATA段内容,找到与objc相关的信息.
        注册objc类
        确保selector的唯一性
        读取protocol以及category的信息
        load_images:函数作用就是调用objc的load方法,它监听dyld_image_state_dependents-initialize通知
        unmap_image可以理解为map_2_images的逆向操作.
        以上3步都是修改__DATA segment中的内容.
    
        4.静态初始化工作,例如load函数,c++的一些初始化构造函数
        5.执行完上述的fix-ups之后,接着就会调用mian()
        
    方法:
        优化__data__,即去除无用的类,方法,属性,分类 
    
    

    9.DSYM是什么

    从Mach-o文件中抽取调试信息(二进制地址对,源码文件,行号以及函数名字的对应关系)而得到的文件目录,实际用于保存调试信息的是.dSYM文件中的DWARF,可以手动生成.
    查看.dSYM文件内容:dwarfdump -v ClangDemo.app.dSYM

    10.Xcode中的clang

    警告提示:Incomplete objective-c protocols等等

    11.lldb调试

    app运行断点调试时,以下列出以下几个比较有用的lldb调试方法

    • thread return直接跳出方法:
    • expression修改值 ,比如 expression name = @"张三"
    • bt 10堆栈打印10条,也可以直接bt
    • thread return 跳出方法

    相关文章

      网友评论

        本文标题:Clang探究及应用

        本文链接:https://www.haomeiwen.com/subject/abqzohtx.html