初识Mach-O文件

前言:本文旨在介绍iOS中的Mach-O文件。

一、介绍

Mach-O是一种文件的格式(可执行文件的格式,比如图片的格式是png,可执行文件的格式是Mach-O),是iOS/Mac OS上存储程序以及库的标准格式。

二、基本结构

Mach-O文件的基本结构:
  • Header:头部,包含可以执行的CPU架构,比如x86,arm64。
  • Load commands:加载命令,也就是告诉系统如何去处理不同的加载信息。包含文件的组织架构和在虚拟内存中的布局方式。
  • Data:数据,包含Load commands中需要的各个段(segment)的数据,每个Segment的大小都是Page的整数倍。
Mach-O文件的基本结构

三、Load Commands

Load Commands

从上图可知 Load Commands 主要包含了有多个 Segment 段,每个 Segment 中又包含了多个 Section 段。每一部分都是系统执行指令。可以看到主要包含了以下几个Segment段:

  • __TEXT段:主要包含程序代码和只读的常量,这个段的内容如果是系统动态库的内容,那么所有进程公用。只读可执行。
  • __DATA段:主要包含全局变量和静态变量,这个段的内容每个进程单独进行维护。可读写。
  • __LINKEDIT:主要包含链接器使用的符号和其他的表(比如函数名称、地址等)这个段的内容也是可以多进程公用。只读。

四、常见的Mach-O文件类型

1、MH_OBJECT
  • 目标文件(.o)
  • 静态库文件(.a),静态库其实就是N个.o合并在一起
2、MH_EXECUTE:可执行文件
  • .app/xx
3、MH_DYLIB:动态库文件
  • .dylib
  • .framework/xx
4、MH_DYLINKER:动态链接编辑器
  • /usr/lib/dyld
5、MH_DSYM:存储着二进制文件符号信息的文件
  • .dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

五、可以查看Mach-O文件的工具

1、MachOView工具

MachOView工具可以在Mac平台中查看MachO文件格式信息。

1.1、MachOView工具下载
MachOView
  • MachOView下载地址:http://sourceforge.net/projects/machoview/
  • MachOView源码地址:https://github.com/gdbinit/MachOView
1.2、MachOView工具使用
  • 直接启动MachOView,在状态栏中点击file,打开对应的MachO文件即可。如下图:


  • 打开后效果如下图,可以查看文件中的信息:


2、Hopper Disassmbler工具

Hopper Disassmbler 可以加载Mach-O文件,显示汇编代码和OC伪代码。

2.1、工具下载
Hopper Disassmbler工具

Hopper Disassmbler下载地址:https://www.hopperapp.com/download.html?

2.2、工具使用
  • 直接启动Hopper Disassmbler,在状态栏中点击file,打开对应的MachO文件即可。如下图:


  • 打开后效果如下图,可以查看文件中的信息:


3、ottol命令可查询Mach-O文件内容

otool可查询需要的内容:

比如输入:otool
    -f print the fat headers
    -a print the archive header
    -h print the mach header
    -l print the load commands
    -L print shared libraries used

终端输入:

otool -h Example

终端输出:

Example:
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
 0xfeedfacf 16777223          3  0x00           2    79       8640 0x00218085

4、size命令可查询Mach-O文件的内存分布

终端输入:

size -l -m -x ZUX

终端输出:

Segment __PAGEZERO: 0x100000000 (zero fill)  (vmaddr 0x0 fileoff 0)
Segment __TEXT: 0x5c8000 (vmaddr 0x100000000 fileoff 0)
    Section __text: 0x522010 (addr 0x100002cc0 offset 11456)
    Section __stubs: 0xca8 (addr 0x100524cd0 offset 5393616)
    Section __stub_helper: 0x1514 (addr 0x100525978 offset 5396856)
    Section __const: 0x84b8 (addr 0x100526e90 offset 5402256)
    Section __cstring: 0x28aed (addr 0x10052f350 offset 5436240)
    Section __objc_methname: 0x479c3 (addr 0x100557e3d offset 5602877)
    Section __ustring: 0xfc8e (addr 0x10059f800 offset 5896192)
    Section __objc_classname: 0x5ac7 (addr 0x1005af48e offset 5960846)
    Section __objc_methtype: 0x9b08 (addr 0x1005b4f55 offset 5984085)
    Section __gcc_except_tab: 0x6630 (addr 0x1005bea60 offset 6023776)
    Section __entitlements: 0x16e (addr 0x1005c5090 offset 6049936)
    Section __unwind_info: 0x2da8 (addr 0x1005c5200 offset 6050304)
    Section __eh_frame: 0x58 (addr 0x1005c7fa8 offset 6061992)
    total 0x5c532f
Segment __DATA: 0x134000 (vmaddr 0x1005c8000 fileoff 6062080)
    Section __nl_symbol_ptr: 0x8 (addr 0x1005c8000 offset 6062080)
    Section __got: 0x598 (addr 0x1005c8008 offset 6062088)
    Section __la_symbol_ptr: 0x10e0 (addr 0x1005c85a0 offset 6063520)
    Section __mod_init_func: 0x10 (addr 0x1005c9680 offset 6067840)
    Section __const: 0x7c50 (addr 0x1005c9690 offset 6067856)
    Section __cfstring: 0x22ce0 (addr 0x1005d12e0 offset 6099680)
    Section __objc_classlist: 0x1e90 (addr 0x1005f3fc0 offset 6242240)
    Section __objc_nlclslist: 0x40 (addr 0x1005f5e50 offset 6250064)
    Section __objc_catlist: 0x250 (addr 0x1005f5e90 offset 6250128)
    Section __objc_nlcatlist: 0x78 (addr 0x1005f60e0 offset 6250720)
    Section __objc_protolist: 0x3e0 (addr 0x1005f6158 offset 6250840)
    Section __objc_imageinfo: 0x8 (addr 0x1005f6538 offset 6251832)
    Section __objc_const: 0xc4dc8 (addr 0x1005f6540 offset 6251840)
    Section __objc_selrefs: 0xe008 (addr 0x1006bb308 offset 7058184)
    Section __objc_protorefs: 0xb0 (addr 0x1006c9310 offset 7115536)
    Section __objc_classrefs: 0x1ef0 (addr 0x1006c93c0 offset 7115712)
    Section __objc_superrefs: 0x13c8 (addr 0x1006cb2b0 offset 7123632)
    Section __objc_ivar: 0x5ce0 (addr 0x1006cc678 offset 7128696)
    Section __objc_data: 0x1f730 (addr 0x1006d2358 offset 7152472)
    Section __data: 0x4bf0 (addr 0x1006f1a90 offset 7281296)
    Section __bss: 0x24b8 (addr 0x1006f6680 zerofill)
    Section __common: 0x8d0 (addr 0x1006f8b40 zerofill)
    total 0x131400
Segment __LINKEDIT: 0x474000 (vmaddr 0x1006fc000 fileoff 7307264)
total 0x100b70000

六、Dyld 动态链接器

1、Dyld 动态链接器作用

App开始启动后,系统首先加载可执行文件(Mach-O文件),然后加载动态链接器Dyld。Dyld是一个专门用来加载动态链接库的库。执行从Dyld开始,Dyld从可执行文件依赖的动态库开始,递归加载所有的依赖动态库链接库。

2、Load Dylibs 加载动态库

Dyld会首先读取Mach-O文件的Header和load commonds。然后就知道了这个可执行文件依赖的动态库。例如加载动态库A到内存,接着检查A所依赖的动态库,就这样的递归加载,直到所有的动态库加载完毕。通常一个App所依赖的动态库在100~400个左右,其中大多数都是系统的动态库,它们会被缓存到(共享缓存)dyld share cache,这样读取的效率会很高。

查看Mach-O文件所依赖的动态库,可以通过MachOView的图形化界面(展开Load Command就能看到),也可以通过命令行otool。

3、Dyld用于加载以下类型的Mach-O文件:
  • MH_EXECUTE(可执行文件)
  • MH_DYLIB(动态库)
  • MH_BUNDLE(bundle类型的mach-o文件)

注意:APP的可执行文件、动态库都是由Dyld负责加载的。


以上是有关Mach-O文件的介绍,欢迎补充和指正。

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