概述
Mach-O(Mach Object)是 macOS、iOS 等 Apple 系统使用的可执行文件格式。一个标准的 Mach-O 文件由 三大部分 组成:
┌─────────────────────────────────────┐
│ 1. Header(文件头) │
│ 2. Load Commands(加载命令) │
│ 3. Data(数据段) │
└─────────────────────────────────────┘
1. Header(文件头)
位于文件偏移 0 处,是文件的"身份证"。
核心内容:
| 字段 | 说明 |
|---|---|
| Magic | 0xFEEDFACE (32位) / 0xFEEDFACF (64位) |
| cputype | CPU 架构(X86_64、ARM64 等) |
| filetype | 文件类型(可执行文件、动态库、目标文件等) |
| ncmds | Load Commands 的数量 |
| sizeofcmds | Load Commands 的总大小 |
| flags | 文件特性标志(PIE、ASLR 等) |
作用:告诉系统"这是什么文件、给什么 CPU 用、后面有多少内容"。
2. Load Commands(加载命令)
紧跟在 Header 之后,是"加载说明书"。
常见命令类型:
| 命令 | 作用 |
|---|---|
LC_SEGMENT / LC_SEGMENT_64 | 描述段(Segment)如何映射到内存 |
LC_LOAD_DYLIB | 依赖的动态库列表 |
LC_SYMTAB | 符号表位置 |
LC_DYSYMTAB | 动态符号表位置 |
LC_CODE_SIGNATURE | 代码签名信息位置 |
LC_MAIN | 程序入口点(替代旧的 LC_UNIXTHREAD) |
LC_BUILD_VERSION | 构建版本信息 |
作用:指导 dyld(动态链接器)如何将文件加载到内存、解析依赖、准备执行。
3. Data(数据)
文件的实际内容,按段(Segment)组织。
主要段(Segments)
| 段名 | 权限 | 内容 |
|---|---|---|
__TEXT | 只读、可执行 | 代码(__text)、常量字符串(__cstring)、Objective-C 元数据等 |
__DATA | 可读、可写 | 全局变量(__data)、未初始化数据(__bss)、线程本地存储等 |
__LINKEDIT | 只读 | 链接和加载所需的元数据 |
__LINKEDIT 段详解
包含大量支持动态链接和数据结构:
| 数据类型 | 说明 |
|---|---|
| 符号表 | 函数/变量名与地址的映射关系 |
| 字符串表 | 符号名称的原始字符串存储 |
| 重定位表 | 需要运行时修正的地址列表 |
| 代码签名 | CMS 签名、CDHash、权限声明(Entitlements) |
| 导出表 | 本文件对外暴露的符号 |
| 绑定信息 | 延迟绑定的符号信息 |
总结
| 组成部分 | 核心职责 | 类比 |
|---|---|---|
| Header | 身份识别和基本信息 | 身份证 |
| Load Commands | 告诉系统如何加载 | 说明书 |
| Data | 实际可执行代码和数据 | 货物本身 |
一句话理解:Header 说"我是谁",Load Commands 说"怎么加载我",Data 说"我的内容是什么"。
查看工具
# 查看 Header
otool -h /bin/ls
# 查看 Load Commands
otool -l /bin/ls
# 查看所有符号
nm /bin/ls
# GUI 工具:MachOView、Hopper、IDA Pro