Mach-O文件初识

一、什么是Mach-O文件?

Mach-O 即 Mach Object,它是一种文件格式(Mac OS 二进制可执行文件)。

二、Mach-O 文件内容详解
  • Mach-O 二进制文件由段(segment)组成,可通过 MachOView 查看。
  • 一个segment由零个或者多个section组成,每个section里面会放置不同的数据或代码。
  • segment需要页对齐(Mac OS 页大小4k,iOS 页大小16k),section不一定是页面对齐的。
  • segment、section命名规则:
    (1)segment 名称采用双下划线开头 +全字母大写(如 __DATA);
    (2)section 名称采用双下划线开头+全字母小写(如 __data);

常见segment的含义:
__TEXT:包含可执行代码和其他只读数据
__DATA:包含可所有读写内容,如:全局变量,静态变量等
__LINKEDIT:加载程序(动态链接器)使用的元数据,如:符号,字符串和重定位的表项

常见__TEXT段中section的含义:
__TEXT,__text: 只放置可执行代码(机器码)
__TEXT,__cstring:字符串常量(最终构建产品时会删除其中重复项)
__TEXT,__const:初始化的const变量

常见__DATA段中section的含义:
__DATA,__data:初始化的可变变量,如C字符串和数据数组
__DATA,__la_symbol_ptr:懒符号指针
__DATA,__objc_selrefs:引用的objc方法
__DATA,__objc_classrefs:引用的objc类
__DATA,__objc_superrefs:引用的objc超类
__DATA,__objc_classlist:objc类列表
__DATA,__objc_nlclslist:objc非懒加载类列表
__DATA,__objc_catlist:objc分类列表
__DATA,__objc_nlcatlist:objc非懒加载分类列表
__DATA,__objc_protolist:objc协议列表
__DATA,__objc_protorefs:引用的objc协议

三、Mach-O 文件结构

一个Mach-O文件一般会包含三个主要区域:Header、Load commands、Data。

1、Header 结构

每个Mach-O文件的开始是一个head structure用来标识这个文件是一个Mach-O文件。header中还包含了其他基本文件类型、目标体系结构等信息。

我们先简单看看mach_header(本文以64位为准)结构,通过usr/include/mach-0/loader.h我们可以找到mach_header_64结构体:


struct mach_header_64 {
	uint32_t	magic;		/* mach 魔数标识符 */
	cpu_type_t	cputype;	/* cpu 说明 */
	cpu_subtype_t	cpusubtype;	/* cpu子类型说明 */
	uint32_t	filetype;	/* 文件类型 */
	uint32_t	ncmds;		/* 加载命令条数 */
	uint32_t	sizeofcmds;	/* 所有load commands大小 */
	uint32_t	flags;		/* 标志 */
	uint32_t	reserved;	/* 保留字段 */
};

/* mach_header_64 的魔数字段的常量(64位架构) */
#define MH_MAGIC_64 0xfeedfacf /* 64位 mach 魔数 */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */

(1)cputypecpusubtype 字段常量值定义在 usr/include/mach/machine.h 中:
由于值太多,这里就不贴出来了,感兴趣的可以自己去看一下。下面举两个示例:


#define CPU_ARCH_ABI64          0x01000000      /* 64 bit ABI */

#define CPU_TYPE_ARM            ((cpu_type_t) 12)
#define CPU_TYPE_ARM64          (CPU_TYPE_ARM | CPU_ARCH_ABI64)


/*
 *	ARM subtypes
 */
#define CPU_SUBTYPE_ARM_V7              ((cpu_subtype_t) 9)  /* ARMv7-A and ARMv7-R */


/*
 *  ARM64 subtypes
 */
#define CPU_SUBTYPE_ARM64_ALL           ((cpu_subtype_t) 0)


cputype、cpusubtype示例:

cputype 12   			//表示arm架构CPU
cputype 9				// 表示armv7


cputype 16777228     	//表示arm64架构CPU,(CPU_TYPE_ARM | CPU_ARCH_ABI64) = (12 | 0x01000000) = 0x0100000C, 0x0100000C转换成十进制等于16777228
cpusubtype 0			// 表示arm64通用架构

(2)filetype字段常见的文件类型常量


#define	MH_OBJECT	0x1		/* 源码编译后的文件,文件扩展名.o */
#define	MH_EXECUTE	0x2		/* 二进制可执行文件 */
#define	MH_DYLIB	0x6		/* 动态库 */
#define	MH_DYLINKER	0x7		/* 动态链接器 */
#define	MH_BUNDLE	0x8		/* 运行时加载的代码,文件扩展名.bundle */
#define	MH_DSYM		0xa		/* 带有调试信息(对应二进制文件的符号信息)的文件dsym */

(3)flags 字段常见的常量


#define	MH_NOUNDEFS	0x1		/* 目标文件中没有未定义的引用 */
#define    MH_DYLDLINK	0x4		/* 对象文件是动态链接器的输入,无法再次静态编辑链接 */
#define    MH_TWOLEVEL	0x80		/* 镜像使用两级命名空间 */
#define    MH_WEAK_DEFINES	0x8000		/* 最终链接的镜像包含外部弱符号*/
#define    MH_BINDS_TO_WEAK 0x10000	/* 最终链接的镜像使用弱符号 */
#define	MH_PIE 0x200000			/* 设置此位时, 操作系统将会在随机地址处加载主可执行文件。仅用于MH_EXECUTE文件类型。 */

示例:
flags  0x00218085   // 0x1+0x4+0x80+0x8000+0x10000+0x200000 = 0x00218085

2、Load commands 结构


struct load_command {
	uint32_t cmd;		/* 加载命令类型 */
	uint32_t cmdsize;	/* 命令大小 */
};

(1)加载命令的cmd字段常见的常量值:


#define LC_REQ_DYLD 0x80000000

#define	LC_SEGMENT	0x1	/* 文件映射的段 */
#define	LC_SYMTAB	0x2	/* 链接编辑stab符号表信息 */
#define	LC_SYMSEG	0x3	/* 链接编辑gdb符号表信息(已过时) */
#define	LC_THREAD	0x4	/* 线程 */
#define	LC_UNIXTHREAD	0x5	/* Unix线程(包括堆栈) */
#define	LC_DYSYMTAB	0xb	/* 动态链接器符号表信息 */
#define	LC_LOAD_DYLIB	0xc	/* 加载动态链接共享库 */
#define    LC_LOAD_DYLINKER 0xe	/* 加载动态链接器 */
#define	LC_TWOLEVEL_HINTS 0x16	/* 两级命名空间查找提示 */
#define	LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) /* 加载允许丢失的动态链接共享库(所有符号均弱导入)*/
#define	LC_SEGMENT_64	0x19	/* 64位文件映射的段 */
#define    LC_UUID		0x1b	/* uuid */
#define.   LC_RPATH       (0x1c | LC_REQ_DYLD)    /* 运行路径添加 */
#define    LC_CODE_SIGNATURE 0x1d	/* 本地代码签名 */
#define	LC_LAZY_LOAD_DYLIB 0x20	/* 将dylib的加载延迟到首次使用 */
#define	LC_ENCRYPTION_INFO 0x21	/* 加密段 information */
#define	LC_DYLD_INFO 	0x22	/* 压缩的dyld信息 */
#define	LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD)	/* 仅压缩的dyld信息 */
#define    LC_VERSION_MIN_MACOSX 0x24   /* 适用于MacOSX的最低版本 */
#define    LC_VERSION_MIN_IPHONEOS 0x25 /* 适用于iOS的最低版本 */
#define    LC_FUNCTION_STARTS 0x26 /* 函数起始地址的压缩表 */
#define    LC_MAIN (0x28|LC_REQ_DYLD) /* 代替 LC_UNIXTHREAD */
#define    LC_DATA_IN_CODE 0x29 /* __text中的非指令表  */
#define    LC_SOURCE_VERSION 0x2A /* 用于构建二进制文件的源代码版本 */
#define	LC_ENCRYPTION_INFO_64 0x2C /* 64位加密段信息 */
#define    LC_BUILD_VERSION 0x32 /* 适用于构建平台OS最低版本 */

具体的命令结构这里就不多做介绍了,请自行查看:usr/include/mach-0/loader.h

四、通用二进制可执行文件
五、常见应用场景
六、参考资料

完整优秀版请移步小专栏:
Mach-O文件初识

更多好文推荐,扫描下方的二维码,关注《iOS开发秘籍》公众号,免费解锁完整版
在这里插入图片描述

本文内容中部分来自网络,后续会持续更新完善。欢迎一起学习交流!

如需转载,请注明出处

Mach-O文件初识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值