CC的博客

  • 首页
  • iOS
  • Android
  • React-Native
  • 读书杂谈
  • About
CC
记录美好生活
  1. 首页
  2. 技术编程
  3. iOS
  4. 正文

Mach-O文件初识

2021/06/07

Mach-O是Mach object的缩写,是Mac/iOS上用于存储程序、库的标准格式

在xnu内核源码中,查看Mach-O类型的部分定义如下(在fat.h和loader.h文件中有全部的类型定义)

#define    MH_OBJECT   0x1     /* relocatable object file */
#define    MH_EXECUTE  0x2     /* demand paged executable file */
#define    MH_FVMLIB   0x3     /* fixed VM shared library file */
#define    MH_CORE     0x4     /* core file */
#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 */

MH_OBJECT
目标文件(.o)或静态库文件(.a),静态库其实就是N个.o文件合并在一起

$ file test.o
test.o:Mach-O 64-bit object x86_64
$ file test.a
test.a: Mach-O universal binary with 5 architectures: [arm_v7:current ar archive random library] [arm_v7s:current ar archive random library] [i386:current ar archive random library] [x86_64:current ar archive random library] [arm64:current ar archive random library]
test.a (for architecture armv7):    current ar archive random library
test.a (for architecture armv7s):   current ar archive random library
test.a (for architecture i386): current ar archive random library
test.a (for architecture x86_64):   current ar archive random library
test.a (for architecture arm64):    current ar archive random library

MH_EXECUTE 可执行文件

$ file Wechat
Wechat: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O executable arm_v7] [arm64]
Wechat (for architecture armv7):    Mach-O executable arm_v7
Wechat (for architecture arm64):    Mach-O 64-bit executable arm64

MH_DYLIB dylib动态库或.framework/xxx

$ file dumpdecrypted.dylib 
dumpdecrypted.dylib: Mach-O universal binary with 3 architectures: [arm_v7:Mach-O dynamically linked shared library arm_v7] [arm_v7s:Mach-O dynamically linked shared library arm_v7s] [arm64:Mach-O 64-bit dynamically linked shared library arm64]
dumpdecrypted.dylib (for architecture armv7):   Mach-O dynamically linked shared library arm_v7
dumpdecrypted.dylib (for architecture armv7s):  Mach-O dynamically linked shared library arm_v7s
dumpdecrypted.dylib (for architecture arm64):   Mach-O 64-bit dynamically linked shared library arm64
file UIKit.framework/UIKit 
UIKit.framework/UIKit: Mach-O 64-bit dynamically linked shared library arm64

MH_DYLINKER 动态链接编辑器,例如/usr/lib/dyld

$ file dyld
dyld: Mach-O 64-bit dynamic linker arm64

MH_DSYM 存储着二进制文件符号信息的文件

xx.DSYM/Contents/Resources/DWARF/xx(用于分析App崩溃信息)

$ file CCFM.app.dSYM/Contents/Resources/DWARF/CCFM 
../CCFM: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O dSYM companion file arm_v7] [arm64]
.../DWARF/CCFM (for architecture armv7):    Mach-O dSYM companion file arm_v7
.../DWARF/CCFM (for architecture arm64):    Mach-O 64-bit dSYM companion file arm64

Xcode项目-->build settings-->Mach-O Type 可以查看当前项目编译后的Mach-O文件类型

Mach-O universal binary(通用二进制文件)

同时适用于多种架构二进制文件,也即包含了多种不同架构独立的二进制文件。
- 因为要存储多种架构的代码,通常比单架构的二进制文件大。
- 由于N种架构有公用的资源,所以不会达到单架构的N倍之大。
- 由于执行过程中,只调用一个架构的代码,运行起来和单架构相比不需要额外的内存。
- 由于文件比较大,也被称之为“胖二进制文件”

Xcode项目-->build settings-->Architectures

截屏2021-06-05 下午11.02.49.png

  • Architectures选项代表配置支持哪些架构,默认为$(ARCHS_STANDARD)这是个Xcode环境变量,随着Xcode版本的不同取值不同。比如Xcode 12 为arm64,armv7,Xcode 7为armv7,armv7s。
  • Excluded Architectures选项代表排除哪些架构,假如Architectures设置了arm64,armv7;Excluded Architectures设置了armv7;那么最终打包生产的可执行文件架构就只剩下arm64。假设Architectures设置了arm64,armv7;Excluded Architectures也设置了arm64,armv7;那么最终打包的产物.app里不包含可执行文件。
  • Build Active Architecture Only代表生成的二进制可执行文件是否只包含当前目标架构。例如打包的时候选择某个arm64架构的真机设备,由于Debug模式此选项为Yes所以只会生成arm64架构的可执行文件;由于Release模式此选项为No所以会生成arm64,armv7架构的可执行文件。
$ lipo -info CCFM
Non-fat file: CCFM is architecture: arm64
$ lipo -info CCFM2
Architectures in the fat file: CCFM2 are: armv7 arm64 
$ lipo CCFM2 -thin arm64 -output CCFM_arm64
$ lipo CCFM2 -thin armv7 -output CCFM_armv7
$ lipo -create CCFM_arm64 CCFM_armv7 -output CCFM2

文件结构

Mach-O文件结构包含Header、Load commands、Data端组成。
image

Header内存储着文件类型、架构类型等信息;Load commands内存储着文件在虚拟内存中的逻辑结构和布局信息;Data中存储着Load commands中描述的segment原始数据。
可以借助Xcode自带的命令行工具otool查看Mach-O文件里的信息。

$ otool --version
llvm-otool(1): Apple Inc. version cctools-977.1
otool(1): Apple Inc. version cctools-977.1
disassmbler: LLVM version 12.0.0, (clang-1200.0.32.29)

otool -f 文件路径:查看胖二进制头文件信息

ottol -h 文件路径:查看架构信息

ottol -L 文件路径:查看链接的动态库信息

$ otool -f VMoney
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
    cputype 12
    cpusubtype 9
    capabilities 0x0
    offset 16384
    size 3414064
    align 2^14 (16384)
architecture 1
    cputype 16777228
    cpusubtype 0
    capabilities 0x0
    offset 3440640
    size 4000880
    align 2^14 (16384)
  • fat_magic:魔法数值,在xnu源码中查找到#define FAT_MAGIC 0xcafebabe
  • nfat_arch:代表胖二进制文件包含的架构数量
  • cputype:代表架构类型#define CPU_TYPE_ARM ((cpu_type_t) 12) #define CPU_ARCH_ABI64 0x01000000 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
  • cpusubtype:代表子架构类型CPU_SUBTYPE_ARM_V7 = 9 #define CPU_SUBTYPE_ARM64_ALL ((cpu_subtype_t) 0)
  • offset:代表在Mach-O文件中的偏移量
  • size:代表在文件中的大小
  • align:代表内存对齐大小

可以看出此胖二进制文件包含两种架构,第一个架构是armv7,第二个架构是arm64(0xC=12 (0x01000000 | 0x12) = 0x100000C = 16777228)

$ otool -h VMoney
VMoney (architecture armv7):
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
 0xfeedface      12          9  0x00           2    36       4128 0x00210085
VMoney (architecture arm64):
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
 0xfeedfacf 16777228          0  0x00           2    36       4696 0x00210085

 ```

- magic:魔法数
> #define   MH_MAGIC    0xfeedface  /* the mach magic number */
> #define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
- filetype:代表Mach-O的具体文件类型 `#define MH_EXECUTE  0x2     /* demand paged executable file */`
- ncmds:代表Mach-O文件中加载命令(load commands)的数量
- sizeofcmds:代表Mach-O文件加载命令(load commands)所占的总字节大小
- flags:代表Mach-O文件的标志信息

$ otool -L VMoney
VMoney (architecture armv7):
....
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3512.60.7)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1280.38.0)
VMoney (architecture arm64):
...
/System/Library/Frameworks/CoreData.framework/CoreData (compatibility version 1.0.0, current version 641.6.0)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1280.38.0)

可以看到链接的动态库信息,其实是读取了`Load Commands`里的`LC_LOAD_DYLIB`信息。

也可以借助GUI工具:MachOView查看Mach-O文件的结构。

![image](https://www.ccnext.cn/wp-content/uploads/2021/06/截屏2021-06-06-下午2.49.46.png)

Load Commands里结构如下
![image](https://www.ccnext.cn/wp-content/uploads/2021/06/截屏2021-06-06-下午2.49.46.png)
- LC_SEGMENT(__PAGEZERO):存储着偏移地址。32位下大小为0x4000,64位下大小为0x100000000。
- LC_SEGMENT(__TEXT):代码段
- LC_SEGMENT(__DATA):数据段
- LC_SEGMENT(__LINKEDIT):
- LC_DYLD_DYLINKER:存储着dyld加载信息,默认使用/usr/lib/dyld加载器。
- LC_VERSION_MIN_IPHONEOS:存储着最低支持版本信息。也即是在Xcode项目中设置的Development Target值。
- LC_ENCRYPTION_INFO:存储着加密信息,其中crypt id为0代表未加密,其他值为加密的方式。
- LC_LOAD_DYLD(xxx):表示需要链接哪些动态库。
- LC_CODE_SIGANTURE:存储着签名信息。


### 特殊的Mach-O文件dyld

查看dyld的源码,在dyld2.cpp中发现以下代码
// only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
    const mach_header* mh = (mach_header*)firstPages;
    switch ( mh->filetype ) {
        case MH_EXECUTE:
        case MH_DYLIB:![](https://www.hidevcc.cn/wp-content/uploads/2021/06/截屏2021-06-05-下午11.02.49-300x111.png)
        case MH_BUNDLE:
            break;
        default:
            throw "mach-o, but wrong filetype";
    }

```
说明dyld只能用来加载MH_EXECUTE、MH_DYLIB、MH_BUNDLE三种类型的Mach-O文件。

标签: 暂无
最后更新:2024/07/06

CC

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2020 CC的博客. ALL RIGHTS RESERVED.

Theme Kratos

豫ICP备2023032048号