美文网首页iOS开发
Mach-O文件结构

Mach-O文件结构

作者: 其字德安 | 来源:发表于2018-01-31 21:50 被阅读1662次

    Mach-O类型的文件

    • Mach-O是一种文件的格式; 是iOS/Mac OS上存储程序以及库的标准格式

      • Mach Object
    • Mach-O格式的文件

    #define MH_OBJECT   0x1     /* 目标文件*/
    #define MH_EXECUTE  0x2     /* 可执行文件 */
    #define MH_FVMLIB   0x3     /* fixed VM shared library file */
    #define MH_CORE     0x4     /*核心转储文件 */
    #define MH_PRELOAD  0x5     /* preloaded executable file */
    #define MH_DYLIB    0x6     /* dynamically bound shared library */
    #define MH_DYLINKER 0x7     /* dynamic link editor */
    #define MH_BUNDLE   0x8     /* dynamically bound bundle file */
    #define MH_DYLIB_STUB   0x9     /* shared library stub for static */
                        /*  linking only, no section contents */
    #define MH_DSYM     0xa     /* companion file with only debug */
                        /*  sections */
    #define MH_KEXT_BUNDLE  0xb     /* x86_64 kexts */
    
    • 常见的Mach-O格式的文件

      • MH_OBJECT 目标文件

        • .o

        • .a/ .framework静态库

          • 静态库即多个.o文件存放在一起实现特定的功能
      • MH_EXECUTE 可执行文件

        • .app/MyApp

        • .out

      • MH_DYLIB 动态库

        • .framework/xxx

        • /dylib

      • MH_DYLINKER 动态链接器

        • usr/lib/dyld
      • MH_DSYM 存储二进制文件符号信息的文件

        • .dYSM/Contents/Resources/DWARF/MyApp
      image.png
    • 查看项目targetMach-O文件的类型

      • MH_EXECUTE类型
      image.png

    Mach-O文件的基本结构

    • Mach-O包含三个主要区域

      • Header: 文件类型, 目标架构

      • Load command: 描述文件在虚拟内存中的逻辑与布局

      • Raw segment date: Load command中定义的原始数据

    image.png
    • 使用otool查看Mach-O文件
    ➜ otool -h  DingTalk
    Mach header
          magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedface      12          9  0x00           2    79       7860 0x00218085
    Mach header
          magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedfacf 16777228          0  0x00           2    79       8672 0x00218085
    
    • 使用file查看Mach-O文件
    # 该Mach-O文件类型是 executable  只有armv7指令集
    ➜  HomeDesign3D China.app file HomeDesign3D\ China
    HomeDesign3D China: Mach-O executable arm_v7
    
    # 该Mach-O文件 类型是 executable;  有armv7, arm64指令集是一个通用二进制文件
    ➜  DingTalk.app file DingTalk
    DingTalk: Mach-O universal binary with 2 architectures: [arm_v7: Mach-O executable arm_v7] [arm64]
    DingTalk (for architecture armv7):  Mach-O executable arm_v7
    DingTalk (for architecture arm64):  Mach-O 64-bit executable arm64
    
    • 通用二进制文件

      • universal binary或者Fat binary

      • 含有多个不同架构的独立二进制文件; 故体积较大

      • 执行时, 只会选择一种架构的二进制文件

      image.png
    • 使用MachOView查看Mach-O文件

      • 以查看DingTalk为例
    image.png image.png image.png
    • RAWRVA

      • RV: 虚拟地址

      • RAW: 文件偏移地址(物理地址)

      • RVA: 相对虚拟地址的偏移

    Mach-O结构详解

    Mach Header(arm64)
    • Magic Number : 魔数, 表示支持设备的CPU位数

      • oxFEEDFACE : 表示32位二进制

      • oxFEEDFACF : 表示64位二进制

    • cputypecpusubtype: CPU类型和子类型

    • filetype : Mach-O文件类型

    • ncmdssizeofcmds: 用于加载器的 加载命令的条数和大小

    • flags : 动态链接器dyld的标志

    image.png

    LC_SEGMENT / LC_SEGMENT_64段的详解

    • 常见段

      • __PAGEZERO: 空指针陷阱段

      • _TEXT: 程序代码段

      • __DATA: 程序数据段

      • __RODATA: read only程序只读数据段

      • __LINKEDIT: 链接器使用段

    image.png
    • section段常见字段

      • Segment Name: 该Segment的名称, 用于load_segment

      • VM Address: 该段的虚拟物理地址

      • VM Size: 该段所需要分配的虚拟内存大小(字节)

      • File Offset: 该段在文件中的偏移量

      • File Size: 该段在文件中占据的字节数

      • Maximum VM Protection: 段的页面所需要的最高内存保护

        • ox1: x 执行

        • ox2: w 写

        • 0x4: r 读

      • Initial VM Protection: 段页面初始化的内存保护

      • Number of Sections: 段中section区的数量

      • Flags: 其他标志位

    tips: 小结:

    根据LC_SEGMENT命令 设置进程虚拟内存

    对于每一个段, 将其内容从Mach-O文件加载到内存中

    即从Mach-O文件中的偏移量为 File Offset处加载File Size字节内容到虚拟内存地址VM AddressVM Size字节空间内

    image.png

    段中区section详解

    • 常见区section

      • __text: 主程序代码

      • __stubs, __stub_helper: 用于动态链接的桩

      • __cstring: 程序中c语言字符串

      • __const: 常量

      • __RODATA,__objc_methname: OC方法名称

      • __RODATA,__objc_methntype: OC方法类型

      • __RODATA,__objc_classname: OC类名

      • __DATA,__objc_classlist: OC类列表

      • __DATA,__objc_protollist: OC原型列表

      • __DATA,__objc_imageinfo: OC镜像信息

      • __DATA,__objc_const: OC常量

      • __DATA,__objc_selfrefs: OC类自引用(self)

      • __DATA,__objc_superrefs: OC类超类引用(super)

      • __DATA,__objc_protolrefs: OC原型引用

      • __DATA, __bss: 没有初始化和初始化为0 的全局变量

    image.png

    Load Commmands加载命令中其他信息

    • LC_MAIN

      • 设置程序主线程入口地址栈大小
    image.png
    • LC_CODE_SIGNATURE

      • 包含Mach-O文件的代码签名

      • 没有签名签名不正确, 该进程会被kill, 程序崩溃

    image.png

    Mach-O中动态库的加载

    • 动态库来源

      • 系统提供的动态库

      • 第三方动态库

    • 如图: DingTalk使用大量的系统动态库

      • Mach-O镜像中有很多对外部库以及符号的引用

      • 这些引用将在程序启动时, 由动态链接器 /usr/lib/dyld来执行符号绑定

    image.png
    • 加载动态链接器

      • LC_LOAD_DYLINKER: 内核执行该命令时, 启动dyld
    image.png
    • 获取符号表

      • LC_SYMTAB: 符号地址表

      • LC_DYSYMTAB: 动态符号地址表

    • 加载动态库

      • LC_LOAD_WEAK_DYLIB

      • LC_LOAD_DYLIB

    动态库加载流程小结

    1.0 首先启动dyld动态链接器; 内核根据LC_LOAD_DYLINKER启动/usr/lib/dyld

    2.0 如果Mach-O文件中使用了外部定义的符号或函数, 则会在文本段__TEXT__stubs, __stub_helper区; 区内放着本地未被定义的符号; 编译器在编译源码时会创建对这些未定义符号桩区的调用

    3.0 dyld运行时, 会在符号桩区调用地址上; 添加JMP 到 真实函数地址的指令

    4.0 至于dyld怎么找到指定的动态库中指定的函数地址? 此时dyld将加载Load Command中的LC_LOAD_DYLIB命令

    5.0 LC_LOAD_DYLIB(动态库), dyld将加载每一个指定的库且搜寻匹配的符号

    6.0 当符号匹配时, 将在符号表(由dyld加载LC_SYMTAB, LC_DYSYMTAB获取)查找对应的函数/符号地址

    相关文章

      网友评论

        本文标题:Mach-O文件结构

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