Mach-O系列(二)Header和LoadCommand

##### 1.通用二进制文件

所谓的通用二进制文件,实质上是支持的各种架构的二进制文件打包在一起的文件,通常也称为胖二进制文件。

其共享一个header,系统会根据cputype和subtype匹配合适的二进制文件,可以通过lipo来提取、删除中指定架构部分的二进制代码。由于其与单个架构的Mach-O文件并无本质区别,本文不对此进行深入讨论。

##### 2. 64位架构下的Mach-O

##### 3. Header

bin目录下是可以直接运行的二进制文件,此处以date为例,使用MachOView打开 /bin/date,其结构如下

![Mach-O分段数据](https://upload-images.jianshu.io/upload_images/1712059-b35992843eb42874.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

首先看Header部分

![Mach-O Header](https://upload-images.jianshu.io/upload_images/1712059-1c3936cad543e04c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

文件头一开始是一个Magic Number,在32位下值是0xFEEDFACE,64位下是0xFEEDFACF,再往下是CPU Type 和 CPU SubType,其作用是确保二进制文件且可在当前架构下运行。继续往下是filetype,也就是Mach-O的文件类型,根据apple官方文件的定义,共有以下几种

继续往下,来到Number of Load Commands,和 Size of Load Commands,其提供了加载器加载命令所需的条数和大小,后面的flags则是动态连接器(dyld)的标志,最后的保留位是64位独有,供未来使用。

##### 3. Load Commands(加载命令)

Header之后紧接着的是Load Command,如下

![Load Commands分段](https://upload-images.jianshu.io/upload_images/1712059-906bf65309c658fd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

以_TEXT为例

![_TEXT](https://upload-images.jianshu.io/upload_images/1712059-aa6d7c42f11652aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![image.png](https://upload-images.jianshu.io/upload_images/1712059-a4d37d1e0d1c23c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

其第一个参数是Command,为Load Commands的类型,其值为LC_SEGMENT_64,该参数的作用是用于将文件中的段映射到进程的地址空间中。

##### 5.LC_SEGMENT_64/LC_SEGMENT

这是最常见的一种LoadCommand,其作用是指导内核如何设置新运行的进程的内存空间,在载入的时候,这些段会从Mach-O文件中载入到内存中。每条LC_SEGMENT_64都提供了段布局所需要的必要信息:

VM Address是描述段的虚拟内存地址,

VM Size是段分配的虚拟内存大小;

File Offset表示段在内存中的偏移量;

File Size表示段在文件中所占的大小;

Max VM Protection为段的页面所需要的最高内存保护,其表示方法是八进制(r=4,w=2,x=1);

Initial Max VM Protection为段的页面最初的内存保护;

Number of Sections表示段中的Section的数量

flags 用于杂项

设想一下,有了LC_SEGMENT_64之后,程序载入内存时,对于每个段,只需要按照偏移量,从File Offset处加载File Size大小的内容到虚拟内存的VM Address处,其大小为VM Size。根据Initial Max VM Protection设置了段的保护级别,后面可以动态改变,前提是不大于Max VM Protection。

先来看第一个_PAGEZERO,其提供了空指针陷阱机制。

_TEXT段是用于存放程序代码的,

_DATA段是用于存放程序数据

_LINKEDIT存放了连接器使用的符号表和其他表

你可能感兴趣的:(Mach-O系列(二)Header和LoadCommand)