概述
iOS App编译之后生成的文件主要包含两部分:资源文件、可执行文件。有时候可能需要分析该可执行文件的组成,这时候可以使用Xcode生成的Link Map File。
怎样生成Link Map File
Link Map File在Xcode的默认选项中是不生成的,需要手动打开。具体方法如下:
Xcode->Build Setting->Linking->Write Link Map File设置为YES,并在Path to Link Map File中设置存储路径。
编译后,到如下目录找到该文本文件:
~/Library/Developer/Xcode/DerivedData/xxx/Build/Intermediates/xxx.build/Debug-iphoneos/xxx.build/
文件名如下:
项目名-LinkMap-平台名.txt
Link Map File文件的结构
整个Link Map File文件分为若干section,每个section描述一类信息,具体来说:
首先是目标文件列表
Object files:
[ 1] /Users/xxx/Library/Developer/Xcode/DerivedData/xxx-fsjhasudsqcpnfanlqqibstjbhsb/Build/Intermediates/xxx.build/Debug-iphonesimulator/xxx.build/Objects-normal/i386/AppDelegate+BackgroundLoadService.o
…
如果该.o文件是通过链接某个静态库导入的,也能看出来,如:
[529] /Users/xxx/Library/Developer/Xcode/DerivedData/xxx-fsjhasudsqcpnfanlqqibstjbhsb/Build/Products/Debug-iphonesimulator/xxx.a(ThirdPartyHandler.o)然后是一个段表,描述了编译生成的各个段在可执行文件中的偏移及大小,主要是包含指令的代码段(TEXT)和包含数据的数据段(DATA)
Sections:
Address Size Segment Section
0x000038E0 0x01D1AD00 _TEXT text
0x01D1E5E0 0x00002094 _TEXT symbol_stub
0x01D20674 0x00002582 _TEXT stub_helper
0x01D22BF6 0x000E476C _TEXT objc_methname
0x01E07362 0x00015DCA _TEXT objc_classname
0x01E1D12C 0x0001E4B1 _TEXT objc_methtype
…最后是符号段,描述了每个符号的偏移地址、所在文件及符号名。符号所在的文件是通过使用目标文件列表中的文件编号表示的。
Symbols:
Address Size File Name
0x000038E0 0x000000A0 [ 1] -[NSDictionary(valueForKeyWithOutNSNull) valueForKeyWithOutNSNull:]
0x00003980 0x00000070 [ 1] -[NSDictionary(valueForKeyWithOutNSNull) valueForKeyWithReturnEmptyString:]
0x000039F0 0x0000007E [ 1] -[NSDictionary(valueForKeyWithOutNSNull) intValueWithDefaultVaule:]
0x00003A70 0x000002C0 [ 2] -[QYFocusScrollView initWithFrame:numberOfPage:]
总结
Link Map File本质上是链接器在链接时输出的一个文本文件,这个文件描述了App可执行文件大致的组成结构。在精简App包大小的时候,有时候需要了解具体的某个库或者某个函数在最终的可执行文件中所占的大小,这个时候Link Map File就派上了用场,它可以给优化提供方向。
其它平台上也有类似的工具,如Windows平台上的dumpbin命令,Linux平台上也有相应的命令。其实无论Windows、Linux还是iOS,其二进制格式都是类似的,无非是先带一个特有的header,随后加上一系列的sections,代码和数据分开存储。详细可以参考《程序员的自我修养》、《Links and Loaders》。
说句题外话,其实有时候了解一些单纯代码之外的东西,能让自己对程序及计算机的理解进一步加深,当时在学校的时候,看了《程序员的自我修养》,现在细节基本上都忘了,但是对各平台可执行文件格式的关系的印象还是很深,Linux下使用的ELF文件和Windows下使用的PE文件都是从Unix系统的COFF文件格式演化而来,无非是增加了一些平台特有的东西,但是大体的结构是相同的,iOS平台没有特别研究,但如果知道iOS平台来历的话,想来应该也差不了太多。
了解一些可执行文件的知识,不仅对优化二进制可执行文件方面有帮助,更重要的是能让你明白了链接器在生成可执行文件的过程中做了什么事情,比如如何收集各静态库的symbol、遇到没有resolve的symbol如何处理;动态链接是怎样实现的;做可执行文件的二进制重排为什么能提高程序的加载效率等等。这些东西的细节不一定要很清楚(实际上99.99%的人终其职业生涯都不会涉及编译器和链接器方面的开发),但是知道概念很重要,这样才能在出现了比如诡异的问题,如奇怪链接错误之后不会无从下手。
最后用引用林语堂先生的一句话自勉:“只用一样东西,不明白它的道理,实在不高明”。当然,人的精力有限,具体深究哪方面,到什么程度,那就是另一个问题了。我的建议是,适当聚焦、最好能和当前工作或兴趣相关,深入到可以用自己的话描述整个过程的大体原理为准,这样才能很自然地将其纳入自己的知识体系。























