赞
踩
加载流程总结
XNU
加载 MachO 可执行文件
和 dyld 动态链接器文件
的大体流程其实很简单:
创建进程 -> 创建虚拟内存空间 ->
解析和映射 MachO 可执行文件
->
解析和映射 dyld 动态链接器文件
->
进入动态链接器 dyld
的执行流程
以下只是简述了 XNU
加载 MachO 可执行文件
和 dyld 动态链接器文件
的大体的流程
下文的分析中,需要大家根据源码和注释进行反复多次理解,这样才能真正了解整个流程和这个流程中的细节
XNU 源码版本
本文所使用的 XNU 源码版本为:xnu-6153.61.1
可以到苹果官网下载相应版本的 XNU
XNU 源码分析
① 首先,我们来到:xnu - 6153.61.1\bsd\kern\kern_exec.c
找到 load_init_program(...)
函数
load_init_program(...)
函数用于加载系统的初始化进程 launchd
launchd
是一个用于管理进程的后台守护进程(daemon:守护进程的意思)
在非 Debug
模式下,只会加载 "/sbin/launchd"
参数 proc_t p
表示由操作系统底层创建出来的原始进程
其中,init_programs[]
就是用于存储守护进程路径的数组
在内核的 debug 模式
下,可以加载用于调试的 launchd.debug
或 launchd.development
在非 debug 模式
下,只加载 launchd
,用于进程管理
② load_init_program_at_path(...)
函数用于验证输入参数和前置条件
并构造用于调用 execve(...)
函数的参数
③ execve(...)
函数底层调用 __mac_execve(...)
函数,用于:
在父进程中 fork
出一个子进程,并在子进程中调用 exec 函数
启动新的程序(即执行一个新的程序)
④ exec_activate_image(...)
函数用于按照文件的格式分发内存映射的函数,目前支持的文件的格式有 3 种:
execsw(...)
函数进行内存映射)上层也可直接调用 posix_spawn(...)
函数生成新进程,posix_spawn(...)
函数会自动调用 exec_activate_image(...)
函数:
数组 execsw[]
的定义如下:
⑤ exec_mach_imgact(...)
函数主要完成了以下几个过程:
vfork(...)
函数生成新的线程(vfork(...)
函数会生成进程,但不会生成线程)调用的子函数 load_machfile(...)
)
exec_fat_imgact(...)
函数用于处理胖二进制文件(通用二进制文件)
exec_shell_imgact(...)
函数用于处理 Shell 脚本
这两个函数不是重点,我们只看一下它俩的定义:
⑥ load_machfile(...)
函数位于 \xnu - 6153.61.1\bsd\kern\mach_loader.c
中,用于 MachO 可执行文件的加载(不包含 MachO 可执行文件的解析):
task
分配可执行内存,task
是一个任务实例,负责进程内的虚拟内存空间,线程管理等工作ASLR 偏移量
的随机exec_mach_imgact(...)
函数回传结果
其中, vm_map_create(..)
函数用于创建虚拟内存映射,底层调用了 vm_map_create_options(..)
函数
vm_compute_max_offset(...)
函数则用于获取不同 CPU 架构的最大的虚拟内存空间
这两个函数都位于 \xnu - 6153.61.1\osfmk\vm\vm_map.c
中
⑦ parse_machfile(...)
函数主要完成了以下几个工作:
MachO
可执行文件的解析,相关 segment
虚拟内存分配dyld
动态链接器文件的加载(调用的子函数 load_dylinker(...)
)dyld
动态链接器文件的解析及虚拟内存分配注意:内核(XNU)并不关心 MachO 中具体 Section(节)的内容,即不解析 Section 的具体信息,而是以 Segment(段) 为单位进行映射
⑧ load_dylinker(...)
函数用于加载动态链接器 dyld
的可执行文件
并调用步骤 ⑦ 中的 parse_machfile(...)
函数,进行 dyld
的解析与虚拟内存分配:
App 在虚拟内存中的分布
① 虚拟内存
: 我们开发者在开发过程中所接触到的内存均为虚拟内存,虚拟内存使 App 认为它拥有连续可用的内存空间(一个连续完整的地址空间),而实际上,App 通常是分布在多个物理内存碎片中,系统的虚拟内存空间映射表(vm_map)负责管理虚拟内存和物理内存的映射关系
文中所提的内存均为虚拟内存。共享动态库其实就是共享的物理内存中的那份动态库,App 虚拟内存中的共享动态库并未真实分配物理内存,使用时虚拟内存会访问同一份物理内存达到共享动态库的目的
iPhoneXr 的物理内存(RAM)只有3GB,那么当超过 3GB 的物理内存时,iOS 是如何处理的呢?
系统会使用一部分硬盘空间(ROM)来充当内存使用,在需要时进行数据交换。当然,硬盘的数据交换速度是远远慢于物理内存的,这也是我们内存过载时,App 卡顿的原因之一
② ASLR
: Address Space Layout Randomization,是一种针对缓冲区溢出漏洞的安全保护技术,通过对 堆、栈、共享库映射等 线性区布局的随机化,通过增加攻击者预测目的地址的难度,达到保护的目的。注意:ASLR
只是随机了线性区布局的起始地址,而不改变线性区里面内容的顺序
③ 以 Arm64
架构为例,根据上面对 XNU
源码的分析可知:
我们大体可以得出一个 App 的虚拟内存分布,如下图所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。