摘录:其字德安「Mach-O文件结构」
(以此记录一下)
iOS上的可执行文件相当于windows上的.exe可执行文件。
在iOS上,主要的可执行文件格式是Mach-O格式。
iOS程序包是.ipa文件。解压缩后里面会有一个payload文件夹,文件夹里有一个.app文件,右键显示包内容,然后找到一个一般体积最大跟.app同名的文件,那个文件就是可执行文件。
Mach-O
类型的文件
-
Mach-O
是一种文件的格式; 是iOS/Mac OS
上存储程序以及库的标准格式Mach Object
-
Mach-O
格式的文件-
EXTERNAL_HEADERS/mach-o/fat.h loader.h
-
#define MH_OBJECT 0x1 /* 目标文件*/
#define MH_EXECUTE 0x2 /* 可执行文件 */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /*核心转储文件 */
#define MH_PRELOAD 0x5 /* preloaded executable file */
#define MH_DYLIB 0x6 /* dynamically bound shared library */
#define MH_DYLINKER 0x7 /* dynamic link editor */
#define MH_BUNDLE 0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB 0x9 /* shared library stub for static */
/* linking only, no section contents */
#define MH_DSYM 0xa /* companion file with only debug */
/* sections */
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */
常见的Mach-O
格式的文件
1、`MH_OBJECT` 目标文件
*`.o`
*`.a/ .framework`静态库
*静态库即多个`.o`文件存放在一起实现特定的功能
2、`MH_EXECUTE` 可执行文件
*`.app/MyApp`
*`.out`
3、 `MH_DYLIB` 动态库
*`.framework/xxx`
*`/dylib`
4、`MH_DYLINKER` 动态链接器
*`usr/lib/dyld`
5、`MH_DSYM` 存储二进制文件符号信息的文件
*`.dYSM/Contents/Resources/DWARF/MyApp`
如图:
image
查看项目target
的Mach-O
文件的类型
MH_EXECUTE
类型
如图:
Mach-O
文件的基本结构
Mach-O
包含三个主要区域
1、`Header`: 文件类型, 目标架构
2、`Load command`: 描述文件在虚拟内存中的逻辑与布局
3、`Raw segment date`: `Load command`中定义的原始数据
image
- 使用
otool
查看Mach-O
文件
➜ otool -h DingTalk
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 12 9 0x00 2 79 7860 0x00218085
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777228 0 0x00 2 79 8672 0x00218085
- 使用
file
查看Mach-O
文件
# 该Mach-O文件类型是 executable 只有armv7指令集
➜ HomeDesign3D China.app file HomeDesign3D\ China
HomeDesign3D China: Mach-O executable arm_v7
# 该Mach-O文件 类型是 executable; 有armv7, arm64指令集是一个通用二进制文件
➜ DingTalk.app file DingTalk
DingTalk: Mach-O universal binary with 2 architectures: [arm_v7: Mach-O executable arm_v7] [arm64]
DingTalk (for architecture armv7): Mach-O executable arm_v7
DingTalk (for architecture arm64): Mach-O 64-bit executable arm64
-
通用二进制文件
-
universal binary
或者Fat binary
-
含有多个不同架构的独立二进制文件; 故体积较大
-
执行时, 只会选择一种架构的二进制文件
-
-
使用
MachOView
查看Mach-O
文件- 以查看
DingTalk
为例
- 以查看
-
RAW
与RVA
RV
: 虚拟地址
RAW
: 文件偏移地址(物理地址)
RVA
: 相对虚拟地址的偏移
Mach-O
结构详解
-
以分析
DingTalk
arm64指令集
为例子
Mach Header(arm64)
-
Magic Number
: 魔数, 表示支持设备的CPU位数
-
oxFEEDFACE
: 表示32位二进制 -
oxFEEDFACF
: 表示64位二进制
-
-
cputype
和cpusubtype
:CPU
类型和子类型 -
filetype
:Mach-O
文件类型 -
ncmds
和sizeofcmds
: 用于加载器的加载命令
的条数和大小 -
flags
: 动态链接器dyld
的标志
LC_SEGMENT / LC_SEGMENT_64
段的详解
-
常见段
__PAGEZERO
: 空指针陷阱段
_TEXT
: 程序代码段
__DATA
: 程序数据段
__RODATA
:read only
程序只读数据段
__LINKEDIT
: 链接器使用段
-
section段
常见字段Segment Name
: 该Segment
的名称, 用于load_segment
VM Address
: 该段的虚拟物理地址
VM Size
: 该段所需要分配的虚拟内存大小(字节)
File Offset
: 该段在文件中的偏移量
File Size
: 该段在文件中占据的字节数
Maximum VM Protection
: 段的页面所需要的最高内存保护ox1
: x 执行
ox2
: w 写
0x4
: r 读Initial VM Protection
: 段页面初始化的内存保护
Number of Sections
: 段中section
区的数量
Flags
: 其他标志位
段中区section
详解
-
常见区
section
__text
: 主程序代码
__stubs, __stub_helper
: 用于动态链接的桩
__cstring
: 程序中c语言
字符串__const
: 常量__RODATA,__objc_methname
:OC
方法名称
__RODATA,__objc_methntype
:OC
方法类型
__RODATA,__objc_classname
:OC
类名__DATA,__objc_classlist
:OC
类列表
__DATA,__objc_protollist
:OC
原型列表
__DATA,__objc_imageinfo
:OC
镜像信息__DATA,__objc_const
:OC
常量
__DATA,__objc_selfrefs
:OC
类自引用(self
)
__DATA,__objc_superrefs
:OC
类超类引用(super
)
__DATA,__objc_protolrefs
:OC
原型引用
__DATA, __bss
: 没有初始化和初始化为0 的全局变量
Load Commmands
加载命令中其他信息
-
加载动态链接器
LC_LOAD_DYLINKER
: 内核执行该命令时, 启动dyld -
获取符号表
LC_SYMTAB
: 符号地址表
LC_DYSYMTAB
: 动态符号地址表 -
加载动态库
LC_LOAD_WEAK_DYLIB
LC_LOAD_DYLIB
动态库加载流程小结
1.0 首先启动dyld动态链接器; 内核根据LC_LOAD_DYLINKER启动/usr/lib/dyld2.0 如果Mach-O文件中使用了外部定义的符号或函数, 则会在文本段__TEXT有__stubs, __stub_helper区; 区内放着本地未被定义的符号; 编译器在编译源码时会创建对这些未定义符号桩区的调用
3.0 dyld运行时, 会在符号桩区调用地址上; 添加JMP 到 真实函数地址的指令
4.0 至于dyld怎么找到指定的动态库中指定的函数地址? 此时dyld将加载Load Command中的LC_LOAD_DYLIB命令
5.0 LC_LOAD_DYLIB(动态库), dyld将加载每一个指定的库且搜寻匹配的符号
6.0 当符号匹配时, 将在符号表(由dyld加载LC_SYMTAB, LC_DYSYMTAB获取)查找对应的函数/符号地址
网友评论