Mach-O文件

下图是App启动流程的关键节点展示:


Mach-O文件_第1张图片
mach-o_execution.png

Universal Binary

大部分情况下,xxx.app/xxx文件并不是Mach-O格式文件,由于现在需要支持不同CPU架构的iOS设备,所以我们编译打包出来的执行文件是一个Universal Binary格式文件(通用二进制文件,也称胖二进制文件),其实Universal Binary只不过将支持不同架构的Mach-O打包在一起,再在文件起始位置加上Fat Header来说明所包含的Mach-O文件支持的架构和偏移地址信息;

Mach-O文件_第2张图片
通用二进制文件
  • Magic Number字段就是我们常说的魔数(与UNIX的ELF文件一样),加载器通过这个魔数值来判断这是什么样的文件,胖二进制文件的魔数值是0xcafebabe;
  • Number of Architecture 字段是指当前的Fat Binary文件包含了多少个不同架构的Mach-O文件;

Mach-O文件分析

Mach-O文件_第3张图片
Mach-O文件结构

如图:有如下几个部分组成:

  • Header:保存了Mach-O的一些基本信息,包括了平台、文件类型、LoadCommands的个数等等。

  • LoadCommands:这一段紧跟Header,加载Mach-O文件时会使用这里的数据来确定内存的分布。

  • Data:每一个segment的具体数据都保存在这里,这里包含了具体的代码、数据等等。

1.mach_header
Mach-O文件_第4张图片
mach_header.png
2.加载命令 Load Commends

在mach_header之后的是加载命令,这些加载命令在Mach-O文件加载解析时,被内核加载器或者动态链接器调用,指导如何设置加载对应的二进制数据段;

Load Commend的数据结构如下:

struct load_command {
    uint32_t cmd;       /* type of load command */
    uint32_t cmdsize;   /* total size of command in bytes */
};

OS X/iOS发展到今天,已经有40多条加载命令,其中部分是由内核加载器直接使用,而其他则是由动态链接器处理。其中几个主要的Load Commend为LC_SEGMENT, LC_LOAD_DYLINKER, LC_UNIXTHREAD, LC_MAIN等。

3.原始段数据 Raw segment data

原始段数据,是Mach-O文件中最大的一部分,包含了Load Command中所需的数据以及在虚存地址偏移量和大小;一般Mach-O文件有多个段(Segement),段每个段有不同的功能,一般包括:

1). __PAGEZERO: 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用;
2). __TEXT: 包含了执行代码以及其他只读数据。该段数据的保护级别为:VM_PROT_READ(读)、VM_PROT_EXECUTE(执行),防止在内存中被修改;
3). __DATA: 包含了程序数据,该段可写;
4). __OBJC: Objective-C运行时支持库;
5). __LINKEDIT: 链接器使用的符号以及其他表

参考资料:

  • http://oncenote.com/2015/06/01/How-App-Launch/
    1. 《Mac OS X Internals: A Systems Approach》
    1. 《Mac OS X and iOS Internals : To the Apple’s Core》
    1. XNU源代码
    1. The App Launch Sequence on iOS
    1. Mach-O Programming Topics
    1. DYLD Detailed

你可能感兴趣的:(Mach-O文件)