Mach-O为Mach Object文件格式的缩写,它是一种用于可执行文件,目标代码,动态库,内核转储的文件格式。作为a.out格式的替代,Mach-O提供了更强的扩展性,并提升了符号表中信息的访问速度。
Mach-O 文件结构如下图:
另外可以下载MachOView工具查看Mach—O 文件结构。下面是UIKit 的截图
下面主要从以下角度学习Mach-O
- 文件头 mach64 Header
- 加载命令 Load Commands
- Sections
Mach Header
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
/* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
字段 | |
---|---|
magic | 魔数,系统加载器通过改字段快速,判断该文件是用于32位or64位。32位-0xfeedface 64位-0xfeedfacf |
cputype | CPU类型以及子类型字段,该字段确保系统可以将适合的二进制文件在当前架构下运行 |
cpusubtype | CPU指定子类型,对于inter,arm,powerpc等CPU架构,其都有各个阶段和等级的CPU芯片,该字段就是详细描述其支持CPU子类型 |
filetype | 说明该mach-o文件类型(可执行文件,库文件,核心转储文件,内核扩展,DYSM文件,动态库) |
ncmds | 说明加载命令条数 |
sizeofcmds | 表示加载命令大小 |
flags | 标志位,该字段用位表示二进制文件支持的功能,主要是和系统加载,链接相关 |
reserved | 保留字段 |
Load Commands
Mach-O文件包含非常详细的加载指令,这些指令非常清晰地指示加载器如何设置并且加载二进制数据。Load Commands紧紧跟着二进制文件头。
Segment name | |
---|---|
LC_SEGMENT_64 | 将文件中(32位或64位)的段映射到进程地址空间中 |
LC_DYLD_INFO_ONLY | 动态库信息以及地址重定向重要的信息 |
LC_SYMTAB | 符号表地址 |
LC_DYSYMTAB | 动态符号表地址 |
LC_LOAD_DYLINKER | 使用何种动态加载库 |
LC_UUID | 文件的唯一标识 |
LC_VERSION_MIN_MACOSX | 二进制文件要求的最低操作系统版本 |
LC_SOURCE_VERSION | 构建该二进制文件使用的源代码版本 |
LC_MAIN | 设置程序主线程的入口地址和栈大小 |
LC_LOAD_DYLIB | 加载额外的动态库,仔细看这个命令格式,动态库地址和名,当前版本号,兼容版本号,该设计比较合理,如果对于动态库有版本管理能力 |
LC_FUNCTION_STARTS | 函数起始地址表 |
Section
Section name | |
---|---|
__text | 主程序代码 |
__stubs | 用于动态库链接的桩 |
__stub_helper | 用于动态库链接的桩 |
__cstring | 常亮字符串符号表描述信息,通过该区信息,可以获得常亮字符串符号表地址 |
__unwind_info | |
__objc_methname | 保存着Objc 里面selector 的名字 |
__objc_classname | 保存Objc类的名字 |
__objc_methtype | 保存Objc类的一些信息(函数签名) |
__objc_classlist | Objective-C 的类列表 |
__objc_nlclslist | Objective-C 的 +load 函数列表,比 __mod_init_func 更早执行 |
__objc_catlist | categories |
__objc_protolist | protocol |
__objc_imageinfo | 保存文件中objc 执行代码的一些信息 |
__objc_selrefs | 指向selectors 的引用 |
__objc_protorefs | 指向protocol 的引用 |
__objc_classrefs | 指向classes 的引用 |
__objc_superrefs | 指向super classes 的引用 |
__mod_init_func | 初始化的全局函数地址,在 main 之前被调用 |
__bss | 未初始化的静态变量 |
_got | 存储引用符号的实际地址,类似于动态符号表 |
以上仅个人学习记录,有错请指教。🙏