iOS 底层探究:启动优化之基本概念

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

1. 虚拟内存 & 物理内存

早期的数据访问是直接通过物理地址访问的,这种方式有以下两个二进制的运算规则问题:

  • 1、内存不够用
  • 2、内存数据的安全问题

1.1 虚拟内存

针对问题1,我们在进程和物理内存之间增加一个中间层,这个中间层就是所谓的虚拟内存,主要用于解决当多个进程架构工程师同时存在时,对物理内存的管理。架构师和程序员的区别高了CPU的利用率,使多个进程可以指针数组同时、按需加载。所以虚拟内存其本质就是一张虚拟地字符间距加宽2磅怎么设置址和物理地址对应关系的映射表

  • 每个进程都有一个独立的虚拟内存,其地址都是从0开始,大小是4G固定架构师工资的,每个虚拟内存又会划分为一个一个的(页的大小在iOS中是16K,其他的字符型变量是4K),每次加载都是以页为单位加载的,进程间是无法互相访问的,保指针数组证了进程间数据的安全性。
  • 二进制换成十进制算法个进程中,只有部分字符间距功能是活跃的,所以只架构图模板需要将进程中活跃的部分放入物理内存,避免物理内存的浪费架构师工资
  • 当CPU需要访问数据时,首先是访问虚拟内存,然后通过虚拟内存去寻址,即可以理解为在表中找对应的物理地址,然后对相应的物理地址进行访问
  • 如果在访问时,虚拟地址的内容未加载到物理内存,会架构图怎么画发生缺页异常(pagefault),将当前进程阻塞指针掉,此时需要先将数据载入到物理内存,然后再寻址,进行读取。这样就避免了内存浪费

如下图所示,字符型变量虚拟内存与物理内存间的关系

iOS 底层探究:启动优化之基本概念

1.2 内存数据的安全问题:ASLR技术

在上面解释架构图怎么画的虚拟内存中,我们提架构图怎么画Objective-C了虚拟内存的起始地址与大小都是固定的,这意味着,当我们访问时,其数据的地址也是固定的,这会导致我们的数据非常容易被破解,为了解决这个问题,所以苹果为了解决这个问题,在iOS4.3开始引入了ASLR技术。

ASLR的概念:(Address Space Layout Randomization )地址空间配置随机加载,是一种针对缓冲区溢出安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通二进制转化为十进制过增加攻击者预测目的地址的难度,防止攻击者直接定位Objective-C攻击代码位置,达到阻止溢出攻击指针数组的目的的一种技术。

其目的字符型变量的通过利用随机方式配置数据地址空间,使某些敏感数据(例如APP登录注册、支付相关代码)配置到一个恶意程序无法事先获知的地址,令攻击者难以进行攻击。

由于ASLR的存在,导致可执行文件和动态链接库在虚拟内存中的加载地址每次启动都不固定,所以需要在编译时来修复镜像中的资源指针,来指向正确的地址。即正确的内存地址 = ASLR地址 + 偏移值

2. 可执行文件

不同的操作系统,其可执行文架构师指针万用表读数图解的格式也不同。系统内核将可执行文件读取到内存,然后指针根据可执行文件的头签名(magic魔数)判断二进制文件的格式

iOS 底层探究:启动优化之基本概念
其中PE、ELF、Mach-O这三种可二进制转八进制执行文件格式都是COFF(Comm架构图怎么制作and file for指针是什么mat)格式的变种,CO架构图模板FF的主要贡献是目标文件里面引入了“段”的机制,不同的目标文件可以拥有不同数量和不同类型的“段”。

3. 通用二进制文件

因为不同CPU平台支持的指令不同指针式万用表,比如架构arm64x8二进制6,苹果中的通用二进制格式就是将多种架构的Mach-O文件二进制转八进制打包在一起,然后系统根据自己的CPU平台,选择合适的Mach-O,所以通用二进制转化为十进制二进制格式也被称为胖二进制格式二进制计算器,如下图所示

iOS 底层探究:启动优化之基本概念
通用二进制格式的定义在&Objective-Clt;mach-o/fat.h>指针数组和数组指针的区别;中,可以在下载xnu,然后根据xnu -> EXTERNAL_HEADERS ->指针是什么;mach-o中找到该文件,通用二架构图模板进制文件开始的指针式万用表使用方法Fat Headerfat_header结构体,而Fat Archs二进制亡者列车是表示通用二进制文件中有多少个Mach-O,单个Mach-O的描述是通过fat_arch结构体。两个结构体的定义如下:

/*
 - magic:可以让系统内核读取该文件时知道是通用二进制文件
 - nfat_arch:表明下面有多个fat_arch结构体,即通用二进制文件包含多少个Mach-O
 */
struct fat_header {
    uint32_t    magic;      /* FAT_MAGIC */
    uint32_t    nfat_arch;  /* number of structs that follow */
};
/*
 fat_arch是描述Mach-O
 - cputype 和 cpusubtype:说明Mach-O适用的平台
 - offset(偏移)、size(大小)、align(页对齐)描述了Mach-O二进制位于通用二进制文件的位置
 */
struct fat_arch {
    cpu_type_t  cputype;    /* cpu specifier (int) */
    cpu_subtype_t   cpusubtype; /* machine specifier (int) */
    uint32_t    offset;     /* file offset to this object file */
    uint32_t    size;       /* size of this object file */
    uint32_t    align;      /* alignment as a power of 2 */
};

所以,综上所述,

  • 通用二进制文件是苹果公司提出的一种新的二进制文件的存储结构,可以同时存储多种架构的二进制指令,使CPU在读取该二进制文件指针时可以架构是什么意思自动检测并选用合适的架构,以最理想的方式进行读取
  • 由于通用二进制文件会同时存储多种架构,所以比单一架构的二进制文件大很多,会占用字符串逆序输出大量的磁盘空间,但由于系统会自动选择最合适的,不相关的架构代码不会占用内存空间,且执行效率高
  • 还可以通过指令来进行Mach-O的合并与拆分
    • 查看当前Mach-O的架构:lipo -info MachO文件
    • 合并:lipo -create MachO1 MachO指针2 -outp字符间距加宽2磅怎么设置ut 输出架构图模板文件路径
    • 拆分:lipo MachO文件 –thin 架构 –output 输出文件路径

4. Mach-O指针万用表读数图解文件

Mach-O文件是Mach Object文件格式的缩写字符型变量,它是用于可执行文件、动态库架构师工资、目标代码的文件格式。作为a.out架构师式的替代,Mach-O格式提供了更强的扩展性,以及更快架构是什么意思的符号表信息访问速度

熟悉Mach-O文件格式,有助于更好的理解苹果底层的运行机制指针式万用表,更好的掌握dyld加载Mach-O的步骤。

4.1 查看Mach-O文件

如果想要查看具体的Mach-O文件信息,字符是什么可以通过以下两种方式,推荐使用第二种方式,更直观

  • 【方式一】otool终端命令:otool -l Mach-O文件名
  • 【方式二】MachOView工具(推荐):将Mach-O可执行文件拖动到MachOView工具打开

4.2 Mach-O文件格式

对于OS X 和iOS来说,Mach-O是其可执行文件的格式,主要包括以下几objective-c和c++的区别种文指针是什么件类型

  • Executable:可执行文件
  • Dylib:动态链接库
  • Bundle:无指针式万用表法被链接的动态库,只能在运行时使用dlopen加载二进制转换器
  • Image:指的是Executable、Dylib和Bundle的一种
  • Framework:包含Dylib、资源文件和头文件的集合

下面图示是Ma指针式万用表使用方法ch-O 镜像文件格式

iOS 底层探究:启动优化之基本概念
以上是Mach-O文件的格式,一个完成的Ma字符ch-O文件主要分为三大部分:

  • Header Mach-O字符型变量头部:主要是Mach-O的cpu架构,文件类型以及加载命令等信息
  • Load Commands 加载命令二进制换成十进制算法:描述了文件中数据的具体组二进制织结构,不同的数据类型使用不同的加载命令表示
  • Data 数据:数据中的每个段(segment)的数据都保存在这里,段的概念架构是什么意思与ELF文件中段的概念类似。每个段都有Objective-C一个或多个部分,它们放置了具体的数据与代码,主要包含代码,数据,例如符号表,动态符号表等等

4.2.1 Header

M二进制ach-O的Header包含了整个Mach-O文件的关键信息,使得CPU能快速知道Mac-O的基架构图模板本信息,其在Mach.h(路径同前文的fat.h一致)针对32位和64位架构的cp字符串是什么意思u,分别使用了ma二进制怎么算c二进制怎么算h_headermach_header_64结构体来描述Mach-O头部mach_head字符间距在哪里设置er是连接器加载时最先读取的内字符间距加宽2磅怎么设置容,决定了一些基础架构、系统类型、指令条数等信息,这里查看64位架构的mach_header_64结构体定义,相比于32位架构的mach_hea指针式万用表der,只是多了一个reserved保留字段,

/*
 - magic:0xfeedface(32位) 0xfeedfacf(64位),系统内核用来判断是否是mach-o格式
 - cputype:CPU类型,比如ARM
 - cpusubtype:CPU的具体类型,例如arm64、armv7
 - filetype:由于可执行文件、目标文件、静态库和动态库等都是mach-o格式,所以需要filetype来说明mach-o文件是属于哪种文件
 - ncmds:sizeofcmds:LoadCommands加载命令的条数(加载命令紧跟header之后)
 - sizeofcmds:LoadCommands加载命令的大小
 - flags:标志位标识二进制文件支持的功能,主要是和系统加载、链接有关
 - reserved:保留字段
 */
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 */
};

其中filetype主要记录Mach-O的文件类型,常用的有以下几种

#define MH_OBJECT   0x1     /* 目标文件*/
#define MH_EXECUTE  0x2     /* 可执行文件*/
#define MH_DYLIB    0x6     /* 动态库*/
#define MH_DYLINKER 0x7     /* 动态链接器*/
#define MH_DSYM     0xa     /* 存储二进制文件符号信息,用于debug分析*/

相对应的,Header在MachOView中的展示如下

iOS 底层探究:启动优化之基本概念

4.2.2 Load Command二进制转八进制s

在Mach-O文件中,Load Commands主要是用于加载指令,其大小和数目在Header中已经被提供,其在M指针是什么ach.h中的定义如下

/*
 load_command用于加载指令
 - cmd 加载命令的类型
 - cmdsize 加载命令的大小
 */
struct load_command {
    uint32_t cmd;       /* type of load command */
    uint32_t cmdsize;   /* total size of command in bytes */
};

我们在MachOView中查看Load Commands,其中记录了很多信息,例如动态链接器的位置、程序的入口、依赖库的信息、代码的位置、符号表的位置等等,如下所示

iOS 底层探究:启动优化之基本概念
其中LC_SEGMENT_64的类型segment_command_64定义如下

/*
 segment_command 段加载命令
 - cmd:表示加载命令类型,
 - cmdsize:表示加载命令大小(还包括了紧跟其后的nsects个section的大小)
 - segname:16个字节的段名字
 - vmaddr:段的虚拟内存起始地址
 - vmsize:段的虚拟内存大小
 - fileoff:段在文件中的偏移量
 - filesize:段在文件中的大小
 - maxprot:段页面所需要的最高内存保护(4 = r,2 = w,1 = x)
 - initprot:段页面初始的内存保护
 - nsects:段中section数量
 - flags:其他杂项标志位
 - 从fileoff(偏移)处,取filesize字节的二进制数据,放到内存的vmaddr处的vmsize字节。(fileoff处到filesize字节的二进制数据,就是“段”)
 - 每一个段的权限相同(或者说,编译时候,编译器把相同权限的数据放在一起,成为段),其权限根据initprot初始化。initprot指定了如何通过读/写/执行位初始化页面的保护级别
 - 段的保护设置可以动态改变,但是不能超过maxprot中指定的值(在iOS中,+x和+w是互斥的)
 */
struct segment_command_64 { /* for 64-bit architectures */
    uint32_t    cmd;        /* LC_SEGMENT_64 */
    uint32_t    cmdsize;    /* includes sizeof section_64 structs */
    char        segname[16];    /* segment name */
    uint64_t    vmaddr;     /* memory address of this segment */
    uint64_t    vmsize;     /* memory size of this segment */
    uint64_t    fileoff;    /* file offset of this segment */
    uint64_t    filesize;   /* amount to map from the file */
    vm_prot_t   maxprot;    /* maximum VM protection */
    vm_prot_t   initprot;   /* initial VM protection */
    uint32_t    nsects;     /* number of sections in segment */
    uint32_t    flags;      /* flags */
};

4.2.3 Data

Load Commands后就是Data区域,这个区域存储了具体的只读、可读写代码,例如方法、符号表、字符表指针万用表读数图解、代字符间距在哪里设置码数据、连接器所需的数据(重定向、符号绑定等)。主要是存储具体的数据。其中大多数的Mach-O文件均包含以下三个段:

  • __TEXT 代码段:只读,包括函数,和只读的字objective-c和c++的区别二进制八进制十进制十六进制转换
  • __DATA 数据段:读写,包括字符串逆序输出可读写的全局变量等
  • __LINKEDIT__L字符常量INKEDIT包含了方法和变量的元数据(位置架构师工资,偏移量),以及代码签名等信息。

Data区中,Section占了很大的比例指针SectionMach.h中是以结构体section_64(在arm64架构下)表示,其定义如下

/*
 Section节在MachO中集中体现在TEXT和DATA两段里.
 - sectname:当前section的名称
 - segname:section所在的segment名称
 - addr:内存中起始位置
 - size:section大小
 - offset:section的文件偏移
 - align:字节大小对齐
 - reloff:重定位入口的文件偏移
 - nreloc:重定位入口数量
 - flags:标志,section的类型和属性
 - reserved1:保留(用于偏移量或索引)
 - reserved2:保留(用于count或sizeof)
 - reserved3:保留
 */
struct section_64 { /* for 64-bit architectures */
    char        sectname[16];   /* name of this section */
    char        segname[16];    /* segment this section goes in */
    uint64_t    addr;       /* memory address of this section */
    uint64_t    size;       /* size in bytes of this section */
    uint32_t    offset;     /* file offset of this section */
    uint32_t    align;      /* section alignment (power of 2) */
    uint32_t    reloff;     /* file offset of relocation entries */
    uint32_t    nreloc;     /* number of relocation entries */
    uint32_t    flags;      /* flags (section type and attributes)*/
    uint32_t    reserved1;  /* reserved (for offset or index) */
    uint32_t    reserved2;  /* reserved (for count or sizeof) */
    uint32_t    reserved3;  /* reserved */
};

Se架构是什么意思ctionMachOView中可以看出,主要集中体现在TEXTDATA两段里,如下所示

iOS 底层探究:启动优化之基本概念
其中常见的section,主要有以下一些

s指针数组和数组指针的区别ection – __TEXT说明
__TEXT.__text主程序代码
__TEXT.__cstringC语言字符串
__TEXT.__字符间距constconst 关指针是什么键字修饰字符常量的常量
__TEXT.__stubs用于 Stub 的占位架构是什么意思代码,很多地方称之为桩代码
__TEXT.__stubs_helper当 Stub 无法找到真正的符号地址后的最终指向
__TEXT.__objc_methnameObjective-C 方法名称
__TEXT.__objc_methtypeObjective-C 方法类型
__TEXT.__objc_classnameObjective-C 类名称
section – __DATA说明
__DATA.__data初始化过的可变数据
__DATA.__la_symbo二进制l_ptrlazy binding 的指针表,表中的指针一开始都指向 __stub_helper
__DATA.nl_symb架构工程师ol_ptr非 lazy binding 的指针表,每个表项中的指针都指向一个在装载过程中,被动态链机器搜索二进制转化为十进制完成的符号
__DATA.__const没有初始化过的常量
__DATA.__cfstring程序中使用的 Core Foundati架构是什么意思onObjective-C 字符串(CFS字符间距在哪里设置t指针万用表读数图解ringRefs)
__DATA.__bssBSS,存放为初始化字符间距怎么加宽的全局变量,即常说的静态内存分配
__DATA.__common没有初始化过的符号声明
__DATA.__objc_classlistObjective-C 类列表
__DATA.__objc_protolistObjective-C 原型
__DATA.__objc_imginfoObjective-C 镜像信息
__DATA.__objc_selfrefsObjective-C self 引用
__指针式万用表使用方法DATA.__obj字符型变量c_protorefsObjective-C 原型引用
__DATA.__objc_superrefsObjective-C 超类引用

所以,综上所述,Mach-O的格字符常量式图示,如下所示

iOS 底层探究:启动优化之基本概念

发表评论

提供最优质的资源集合

立即查看 了解详情