iOS开发指南

Clang探究及应用

2020-05-21  本文已影响0人  格雷s

1.前言

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

2.意义

3.Xcode中的编译器发展史

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调试方法

上一篇下一篇

猜你喜欢

热点阅读