美文网首页
Link Map File

Link Map File

作者: 沉江小鱼 | 来源:发表于2020-09-08 17:36 被阅读0次

    1. Link Map File 简介

    Link Map File 直译为 链接映射文件,在编译阶段,每个类会生成对应的.o文件,链接阶段,会把.o文件和动态库链接在一起。Link Map File 就是这样一个记录链接相关信息的纯文本文件,里面记录了可执行文件的路径、CPU架构、目标文件、符号等信息。

    2. Link Map File 作用

    理解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,是一个txt文件:


    截屏2020-09-08 下午5.01.14.png

    Write Link Map File上面就是生成文件的路径:


    截屏2020-09-08 下午5.02.36.png

    通过这个路径可以访问到:

    ~/Developer/Xcode/DerivedData/项目/Build/Intermediates.noindex/项目.build/Debug-iphonesimulator/项目.build/项目-LinkMap-normal-x86_64.txt
    

    在 Products 下找到.app文件,返回上层根据路径找到Link Map文件:

    截屏2020-09-08 下午5.06.24.png

    4. 分析Link Map File

    我们打开Link Map File 文件,然后从上往下去分析:

    4.1 Path & Arch
    Path: /Users/wangce/Library/Developer/Xcode/DerivedData/InjectTest-eqmjuuqdlkmitzgsjehvsiypbwoe/Build/Intermediates.noindex/InjectTest.build/Debug-iphoneos/InjectTest.build/Objects-normal/armv7/Binary/InjectTest
    Arch: armv7
    

    Path是可执行文件的路径,Arch是架构类型。

    4.2 Object files
    # Object files:
    [  0] linker synthesized
    [  1] /Users/wangce/Library/Developer/Xcode/DerivedData/InjectTest-eqmjuuqdlkmitzgsjehvsiypbwoe/Build/Intermediates.noindex/InjectTest.build/Debug-iphoneos/InjectTest.build/Objects-normal/armv7/GCDManager.o
    [  2] /Users/wangce/Library/Developer/Xcode/DerivedData/InjectTest-eqmjuuqdlkmitzgsjehvsiypbwoe/Build/Intermediates.noindex/InjectTest.build/Debug-iphoneos/InjectTest.build/Objects-normal/armv7/ViewController.o
    [  3] /Users/wangce/Library/Developer/Xcode/DerivedData/InjectTest-eqmjuuqdlkmitzgsjehvsiypbwoe/Build/Intermediates.noindex/InjectTest.build/Debug-iphoneos/InjectTest.build/Objects-normal/armv7/PresentTransition.o
    

    在编译成目标文件后,通过链接器进行链接,最终合成可执行文件。这里展示的信息是链接时用到的文件,包括.o文件和dylib库。第一列的序号是类的编号,通过该编号可以对应到具体的类。

    在后面的Symbols部分,我们会用到类的编号。

    4.3 Section 区
    # Sections:
    # Address   Size        Segment Section
    0x0000AF68  0x00002F48  __TEXT  __text
    0x0000DEB0  0x00000270  __TEXT  __picsymbolstub4
    0x0000E120  0x000001F8  __TEXT  __stub_helper
    0x0000E318  0x00000014  __TEXT  __gcc_except_tab
    0x0000E32C  0x00000207  __TEXT  __cstring
    0x0000E533  0x0000105A  __TEXT  __objc_methname
    0x0000F58D  0x00000094  __TEXT  __objc_classname
    0x0000F621  0x000009D9  __TEXT  __objc_methtype
    0x00010000  0x00000020  __DATA  __nl_symbol_ptr
    0x00010020  0x0000009C  __DATA  __la_symbol_ptr
    0x000100BC  0x0000009C  __DATA  __const
    0x00010158  0x00000090  __DATA  __cfstring
    0x000101E8  0x00000014  __DATA  __objc_classlist
    0x000101FC  0x00000004  __DATA  __objc_nlclslist
    0x00010200  0x0000000C  __DATA  __objc_protolist
    0x0001020C  0x00000008  __DATA  __objc_imageinfo
    0x00010214  0x00000B1C  __DATA  __objc_const
    0x00010D30  0x0000011C  __DATA  __objc_selrefs
    0x00010E4C  0x0000003C  __DATA  __objc_classrefs
    0x00010E88  0x00000004  __DATA  __objc_superrefs
    0x00010E8C  0x00000014  __DATA  __objc_ivar
    0x00010EA0  0x000000C8  __DATA  __objc_data
    0x00010F68  0x000000A0  __DATA  __data
    0x00011008  0x00000008  __DATA  __bss
    

    第一列Address是起始位置,第二列Size是Section占用内存大小,第三列是Segment类型,第四列是Section类型。

    我们这里再次补充一点Mach-O的知识:
    Mach-O文件中的虚拟地址最终会映射到物理地址上,这些地址被分成不同的Segment:
    _Text段:包含Mach Header,被执行的代码和只读常量、只读可执行(r-x)
    _DATA段:包含全局变量,静态变量,可读写(rw-)
    _LINKEDIT:包含了加载程序的『元数据』,比如函数的名称和地址,只读(r–)

    Segement划分成了不同的Section,不同的Section存储着不同的信息,下面是一些常用的Section的介绍:

    //  __TEXT段中的一些Section
    1. __text: 代码节,存放机器编译后的代码
    2. __stubs: 用于辅助做动态链接代码(dyld).
    3. __stub_helper:用于辅助做动态链接(dyld).
    4. __objc_methname:objc的方法名称
    5. __cstring:代码运行中包含的字符串常量,比如代码中定义`#define kGeTuiPushAESKey        @"DWE2#@e2!"`,那DWE2#@e2!会存在这个区里。
    6. __objc_classname:objc类名
    7. __objc_methtype:objc方法类型
    8. __ustring:
    9. __gcc_except_tab:
    10. __const:存储const修饰的常量
    11. __dof_RACSignal:
    12. __dof_RACCompou:
    13. __unwind_info:
    
    // __DATA段中的一些Section
    1. __got:存储引用符号的实际地址,类似于动态符号表
    2. __la_symbol_ptr:lazy symbol pointers。懒加载的函数指针地址。和__stubs和stub_helper配合使用。具体原理暂留。
    3. __mod_init_func:模块初始化的方法。
    4. __const:存储constant常量的数据。比如使用extern导出的const修饰的常量。
    5. __cfstring:使用Core Foundation字符串
    6. __objc_classlist:objc类列表,保存类信息,映射了__objc_data的地址
    7. __objc_nlclslist:Objective-C 的 +load 函数列表,比 __mod_init_func 更早执行。
    8. __objc_catlist: categories
    9. __objc_nlcatlist:Objective-C 的categories的 +load函数列表。
    10. __objc_protolist:objc协议列表
    11. __objc_imageinfo:objc镜像信息
    12. __objc_const:objc常量。保存objc_classdata结构体数据。用于映射类相关数据的地址,比如类名,方法名等。
    13. __objc_selrefs:引用到的objc方法
    14. __objc_protorefs:引用到的objc协议
    15. __objc_classrefs:引用到的objc类
    16. __objc_superrefs:objc超类引用
    17. __objc_ivar:objc ivar指针,存储属性。
    18. __objc_data:objc的数据。用于保存类需要的数据。最主要的内容是映射__objc_const地址,用于找到类的相关数据。
    19. __data:暂时没理解,从日志看存放了协议和一些固定了地址(已经初始化)的静态量。
    20. __bss:存储未初始化的静态量。比如:`static NSThread *_networkRequestThread = nil;`其中这里面的size表示应用运行占用的内存,不是实际的占用空间。所以计算大小的时候应该去掉这部分数据。
    21. __common:存储导出的全局的数据。类似于static,但是没有用static修饰。比如KSCrash里面`NSDictionary* g_registerOrders;`, g_registerOrders就存储在__common里面
    

    虚拟内存最终会映射到物理内存,通过上面的介绍,我们就可以知道代码和数据在内存中是如何存储的。

    4.4 Symbols
    # Symbols:
    // __text代码区
    # Address   Size        File  Name
    0x0000AF68  0x0000005E  [  1] +[GCDManager sharedInstance]
    0x0000AFC6  0x00000052  [  1] ___28+[GCDManager sharedInstance]_block_invoke
    0x0000B018  0x00000470  [  1] -[GCDManager scheduledDispatchTimerWithName:timeInterval:queue:repeats:action:]
    0x0000B488  0x00000064  [  1] ___79-[GCDManager scheduledDispatchTimerWithName:timeInterval:queue:repeats:action:]_block_invoke
    0x0000B4EC  0x00000064  [  1] ___copy_helper_block_e4_20b24s28w
    0x0000B550  0x00000030  [  1] ___destroy_helper_block_e4_20s24s28w
    0x0000B580  0x00000156  [  1] -[GCDManager cancelTimerWithName:]
    0x0000B6D6  0x000000B0  [  1] -[GCDManager cancelAllTimer]
    0x0000B786  0x000000B2  [  1] ___28-[GCDManager cancelAllTimer]_block_invoke
    0x0000B838  0x00000026  [  1] ___copy_helper_block_e4_20s
    0x0000B85E  0x00000016  [  1] ___destroy_helper_block_e4_20s
    0x0000B874  0x0000005E  [  1] -[GCDManager timerContainer]
    0x0000B8D2  0x0000005E  [  1] -[GCDManager actionBlockCache]
    0x0000B930  0x000001FC  [  1] -[GCDManager cacheAction:forTimer:]
    0x0000BB2C  0x00000102  [  1] -[GCDManager removeActionCacheForTimer:]
    0x0000BC2E  0x00000020  [  1] -[GCDManager setTimerContainer:]
    0x0000BC4E  0x00000020  [  1] -[GCDManager setActionBlockCache:]
    0x0000BC6E  0x00000028  [  1] -[GCDManager .cxx_destruct]
    0x0000BC98  0x000008C0  [  2] -[ViewController viewDidLoad]
    0x0000C558  0x00000046  [  2] _CGRectMake
    0x0000C59E  0x00000104  [  2] -[ViewController delNum]
    0x0000C6A2  0x00000104  [  2] -[ViewController addNum]
    0x0000C7A6  0x0000002A  [  2] -[ViewController delBtn]
    0x0000C7D0  0x0000002A  [  2] -[ViewController addBtn]
    0x0000C7FA  0x00000248  [  2] -[ViewController configNum:]
    0x0000CA42  0x000000DE  [  2] -[ViewController undo]
    ...
    
    // __objc_methname方法名区
    0x0000E369  0x0000000F  [  1] literal string: timerContainer
    0x0000E378  0x0000002D  [  1] literal string: T@"NSMutableDictionary",&,N,V_timerContainer
    0x0000E3A5  0x00000011  [  1] literal string: actionBlockCache
    0x0000E3B6  0x0000002F  [  1] literal string: T@"NSMutableDictionary",&,N,V_actionBlockCache
    0x0000E3E5  0x00000005  [  2] literal string: undo
    0x0000E3EA  0x00000005  [  2] literal string: redo
    0x0000E3EF  0x00000003  [  2] literal string: +1
    0x0000E3F2  0x00000003  [  2] literal string: -1
    0x0000E3F5  0x00000004  [  2] literal string: %ld
    0x0000E3F9  0x0000000D  [  2] literal string: can not undo
    0x0000E406  0x0000000D  [  2] literal string: can not redo
    0x0000E413  0x00000007  [  2] literal string: numLab
    0x0000E41A  0x00000019  [  2] literal string: T@"UILabel",&,N,V_numLab
    0x0000E433  0x00000006  [  2] literal string: index
    0x0000E439  0x0000000D  [  2] literal string: Ti,N,V_index
    0x0000E446  0x00000008  [  3] literal string: v8@?0c4
    0x0000E44E  0x00000005  [  3] literal string: hash
    ...
    
    

    Symbols 部分的 File 顺序是和 Target -> Build Phase -> Compile Sources 的文件顺序一致的。

    相关文章

      网友评论

          本文标题:Link Map File

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