Mach-O文件结构是什么?
摘要:Mach-O文件是Apple各种编译中间产物(比如.o)和最终编译产物(比如可执行二进制)使用的文件格式。 熟悉Mach-O格式,对于我们进行一些底层调试有帮助。 1 整体结构 Mach-O的整体结构如下: 2 Header Mach-O最
Mach-O文件是Apple各种编译中间产物(比如.o)和最终编译产物(比如可执行二进制)使用的文件格式。
熟悉Mach-O格式,对于我们进行一些底层调试有帮助。
1 整体结构
Mach-O的整体结构如下:
2 Header
Mach-O最顶部是头信息。
头信息定义了这个Mach-O的基本信息,比如这个Mach-O使用的CPU架构、文件类型等。
头信息定义在XNU源码macho/loader.h中:
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 */
};
magic
magic使用的常量为MH_MAGIC_64和MH_CIGAM_64。
对这两个值常见的一个误解是,以为MH_MAGIC_64代表Mach-O使用大端字节序,MH_CIGAM_64使用小端字节序。
而实际上是,如果Mach-O使用的字节序和后面cputype指定的CPU使用的字节序一样,那么就是MH_MAGIC_64。
反之,如果Mach-O使用的字节序和后面cputype指定的CPU使用的字节序相反,那么就是MH_CIGAM_64。
cputype
cputype表示这个Mach-O文件要运行的CPU类型,比如是ARM64还是X86_64。
注意到这个字段的类型是cpu_type_t,它的定义如下:
// mach/machine.h
typedef integer_t cpu_type_t;
typedef integer_t cpu_subtype_t;
typedef integer_t cpu_threadtype_t;
// mach/arm/vm_types.h
typedef int integer_t;
从上面代码可以看到,cpu_type_t实际就是一个int类型。
cpusubtype
定义了CPU的子类型,比如CPU_SUBTYPE_ARM64_ALL。
filetype
常见的值如下:
MH_OBJECT表明当前是一个.o文件。
MH_EXECUTE表明当前是一个可执行文件。
MH_DYLIB表明当前是一个动态链接库。
MH_PRELOAD这个类型已经废弃了。
MH_CORE表明当前是一个core文件。
程序崩溃后产生core文件,后续可以直接调试core文件定位问题,但是iOS应用不会产生这个文件类型。
MH_DYLINKER表明当前是一个动态链接器,dyld就是这个类型。
MH_DSYM表明当前是一个.dsym符号文件。
ncmds
文件后后面LC_Command的个数
sizeofcmds
所有LC_Command占用的字节数大小。
flags
常见的flags值如下:
MH_NOUNDEFS表明当前Mach-O内没有未定义的引用。
MH_DYLDLINK表明当前Mach-O只能作为动态连接器的输入,不能再进行静态链接,可执行文件有这个标志。
MH_TOWLEVEL表明当前Mach-O使用二级命名空间,也就是说每一个外部符号都会记录它来自哪个库,避免名称冲突。
MH_PIE表明当前Mach-O会使用ASLR。
3 Load Command
紧接着Mach-O头信息的是一系列Load Command。
Load Command的种类很多,所有的Load Command开头的结构都是一样的:
// mach-o/loader.h
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
cmd
表明当前Load Command的类型。
