文章目录
- iOS编译
- (一)编译器前端
- 编译器后端
- 执行一次XCode build的流程
- IPA包的内容
- 二进制文件的内容
- iOS Link Map File文件说明
- 1. Link Map File 是什么
- 2. Link Map File 有什么用
- 3. 生成 Link Map File
- 查看Link Map File
- 1)路径部分
- 计算机系统知识
- a. __TEXT段中的 Section
- b. __DATA段中的 Section
- (4) Symbols 部分
- (5)二进制重排
一般可以将编程语言分为两种,编译语言和直译式语言。
像C++,Objective C都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。
像JavaScript,Python都是直译式语言。直译式语言不需要经过编译的过程,而是在执行的时候通过一个中间的解释器将代码解释为CPU可以执行的代码。所以,较编译语言来说,直译式语言效率低一些,但是编写的更灵活
iOS编译
Objective C采用Clang(swift采用swiftc)作为编译器前端,LLVM作为编译器后端。
简单的编译过程如图
(一)编译器前端
编译器前端的任务是进行:词法分析,语法分析,语义分析,生成中间代码(intermediate representation )。在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。
编译器后端
编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。iOS的编译过程,后端的处理如下
-
LVVM优化器会进行BitCode的生成,链接期优化等等。
-
LLVM机器码生成器会针对不同的架构,比如arm64等生成不同的机器码。
执行一次XCode build的流程
当你在XCode中,选择build的时候(快捷键command+B),会执行如下过程
编译信息写入辅助文件,创建编译后的文件架构(name.app)
处理文件打包信息,例如在debug环境下
Entitlements:
{
“application-identifier” = “app的bundleid”;
“aps-environment” = development;
}
执行CocoaPod编译前脚本
例如对于使用CocoaPod的工程会执行CheckPods Manifest.lock
编译各个.m文件,使用CompileC和clang命令。
CompileC ClassName.o ClassName.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler
export LANG=en_US.US-ASCII
export PATH=“…”
clang -x objective-c -arch x86_64 -fmessage-length=0 -fobjc-arc… -Wno-missing-field-initializers … -DDEBUG=1 … -isysroot iPhoneSimulator10.1.sdk -fasm-blocks … -I 上文提到的文件 -F 所需要的Framework -iquote 所需要的Framework … -c ClassName.c -o ClassName.o
通过这个编译的命令,我们可以看到
clang是实际的编译命令
-x objective-c 指定了编译的语言
-arch x86_64制定了编译的架构,类似还有arm7等
-fobjc-arc 一些列-f开头的,指定了采用arc等信息。这个也就是为什么你可以对单独的一个.m文件采用非ARC编程。
-Wno-missing-field-initializers 一系列以-W开头的,指的是编译的警告选项,通过这些你可以定制化编译选项
-DDEBUG=1 一些列-D开头的,指的是预编译宏,通过这些宏可以实现条件编译
-iPhoneSimulator10.1.sdk 制定了编译采用的iOS SDK版本
-I 把编译信息写入指定的辅助文件
-F 链接所需要的Framework
-c ClassName.c 编译文件
-o ClassName.o 编译产物
- 链接需要的Framework,例如Foundation.framework,AFNetworking.framework,ALiPay.fframework
- 编译xib文件
- 拷贝xib,图片等资源文件到结果目录
- 编译ImageAssets
- 处理info.plist
- 执行CocoaPod脚本
- 拷贝Swift标准库
- 创建.app文件和对其签名
IPA包的内容
例如,我们通过iTunes Store下载微信,然后获得ipa安装包,然后实际看看其安装包的内容。
二进制文件的内容
通过XCode的Link Map File,我们可以窥探二进制文件中布局。 在XCode -> Build Settings -> 搜索map -> 开启Write Link Map File
![
iOS Link Map File文件说明
1. Link Map File 是什么
Link Map File 直译为 链接映射文件,是 Xcode 生成可执行文件时一起生成的文本,用于记录链接相关信息。
可执行文件的路径
CPU架构
.o目标路径
方法符号
2. Link Map File 有什么用
查看代码加载顺序
理解内存分段分区
Crash 时通过 Symbols 定位源码的机制
分析可执行文件中类或库体积,优化包体积
3. 生成 Link Map File
Xcode 在生成可执行文件的时候默认情况下不生成该文件。 在Xcode的配置中 Target -> Build Setting -> Linking 将Write Link Map File设置为YES来生成Link Map File,运行代码即可生成Link Map File
查看Link Map File
主要分为三个部分
- 路径部分,展示生成的相关文件路径
- Section部分,展示相关地址段
- Symbols部分,方法符号段
1)路径部分
- Path是.app文件路径
- Object files是.o文件路径
计算机系统知识
a. text 段
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
b. data 段
数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。
c. bss 段
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
bss是英文Block Started by Symbol的简称。
d. 堆(heap)
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
e. 栈(stack)
栈又称堆栈,是用户存放程序临时创建的局部变量,
也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。
从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
(3)Section 部分
Mach-O 文件中的虚拟地址最终会映射到物理地址上。这些地址被分成不同的Segement: TEXT段、DATA段、__LINKEDIT段。
__TEXT 包含 Mach header,被执行的代码和只读常量(如C 字符串),只读可执行(r-x)。
__DATA 包含全局变量,静态变量等,可读写(rw-)。
__LINKEDIT 包含了加载程序的元数据,比如函数的名称和地址,只读(r–)。
Segement 划分成了不同的 Section,不同的 Section 存储着不同的信息,下面是一些常用的 Section 的介绍。
a. __TEXT段中的 Section
b. __DATA段中的 Section
(4) Symbols 部分
- Address:方法代码的地址
- Size:方法占用的空间
- File:文件的编号
- Name:.o文件里面的方法符号
(5)二进制重排
二进制重排 就是要重新排列这些 方法符号的顺序 ,中心思想就是把启动用到的代码挪到前面的位置加载!