文章目录
- 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
 
查看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)二进制重排
二进制重排 就是要重新排列这些 方法符号的顺序 ,中心思想就是把启动用到的代码挪到前面的位置加载!




















