1. Page Zero的作用

Making a big __PAGEZERO in a 64-bit architecture makes a whole lot of sense. The address range of a 64-bit system, even when the upper 16 bits are "cropped off" like that of x86_64, allows for a huge amount of memory (the 48-bit address space of x86_64 is 256TB of memory address space). It is highly likely that this will be thought of as "small" at some point in the future, but right now, the biggest servers have 1-4TB, so there's plenty of room to grow, and more ordinary machines have 16-32GB.

Note also that no memory is actually OCCUPIED. It's just "reserved virtual space" (that is, "it will never be used"). It takes up absolutely zero resources, because it's not mapped in the page-table, it's not there physically. It's just an entry in the file, which tells the loader to reserve this space to it can never be used, and thus "safeguarded". The actual "data" of this section is zero in size, since, again, there's actually nothing there, just a "make sure this is not used". So your actual file size won't be any larger or smaller if this section is changed in size. It would be a few bytes smaller (the size of the section description) if it didn't exist at all. But that's really the only what it would make any difference at all.

The purpose of a __PAGEZERO is to catch NULL pointer dereferences. By reserving a large section of memory at the beginning of memory, any access through a NULL pointer will be caught and the application aborted. In a 32-bit architecture, something like:

int *p = NULL;
int x = p[0x100000];

is likely to succeed, because at 0x400000 (4MB) the code-space starts (trying to write to such a location is likely to crash, but reading will work - assuming of course the code-space actually starts there and not someplace else in the address range.

Edit:

This presentation shows that ARM, the latest entrant into the 64-bit processor sapce, is also using 48-bit virtual address space, and enforces canonical addresses (top 16 bits need to all be the same value) so it can be expanded in the future. In other words, the virtual space available on a 64-bit ARM processor is also 256TB.

In addition to catching NULL dereferences, using a size of 0x100000000 in 64-bit means that no 32-bit pointer is valid. This helps catch buggy software that has been compiled for 64-bit but is not 64-bit safe. For example, it copies a pointer to an int and then back to a pointer variable, truncating it.

2. 翻译

让 64 位架构中的 __PAGEZERO 尽可能大有许多意义:

首先,64 系统下,地址够用。虽然很多 64 位架构和 x86_64 架构一样,将 64 中的高 16 位剪掉了,但是仍然有 48 位可以用来表示地址。48 位意味着 256TB 的大小,而如今服务器最大的内存大概是 1-4TB,一般机器的内存时 16-32GB,所以 256TB 在很长一段时间内具备增长的空间,即:够用!

另外,__PAGEZERO 所指代的内存并没有真正被分配(或占用)。首先,在文件在硬盘上时,__PAGEZERO 的 filesize 为 0,即不分配硬盘空间。再者,mach-O 是被加载进入虚拟内存而不是物理内存,物理内存的使用需要通过 MMU 进行印射。因此,__PAGEZERO 占用的虚拟内存在物理内存中并没有被分配。如果程序访问该段内存,肯定会直接被系统拦截,报出 BAD_ACCESS 的错误,即:

  1. 存储在硬盘上时,不占用硬盘空间;
  2. 被加载进入虚拟内存时,不会分配真实的物理内存;
  3. 只是其到一个作用:告诉加载者分配固定内存,告诉使用者这段虚拟内存不能使用;

至此,__PAGEZERO 的使用方式了解了,但是 __PAGEZERO 这段的具体作用是什么?首先是为了判断空指针的异常访问。

如下图,在 macOS 中测试:

pagezero

结果就是 p 虽然是空指针,但是依然访问成功了。

这里 read 是可以的 write 是不行的。write 的限制很多,如类型判断,起始位置判断等等,read 可能只需要判断该虚拟空间是否有印射到真实的物理内存中;

因为 0x100000000 超出了 __PAGEZERO 的范围,再来看一个空指针异常的正常流程:

空指针访问

如上图,0x80000000__PAGEZERO 段内,访问时直接报错;

其实这个测试也可以在 ARM64 的 iphone 上验证,只不过 iOS 中有 Slide,所以需要用 expression 来实时赋值:

iOS中的PageZero

直接访问 0x100000000 会报错,因为 Slide 的原因,该内存未被分配物理内存,也会报 Bad Access;所以这里感觉可以验证指针访问的内存如果没有印射到物理内存的话,实际是会报错的,即:指针访问的有效内存都是已经 Page In 过的,否则就会 Bad Access;

所以,__PAGEZERO 的目的就是为了判断空指针的访问,因此这个地址越大,其有效性就越高。

最后,作用补充了一点,__PAGEZERO 设置成 4GB 的另外一个原因是为了隔绝 32 位系统,比如指针小于 4GB 时,那这大概率是一个 32 位系统的指针,那么指向了 __PAGEZERO 就会直接报错。这就意味着 arm64 架构不支持 32 位的软件了;

总结:

  1. PAGEZERO 在 iOS 中大小为 4GB;
  2. arm64 使用 48 位做内存地址,虚拟内存最大可以是 256TB;
  3. iOS 中源码体现的虚拟内存最大为 64GB (0x10|0000|0000);
  4. PAGEZERO 的目的之一是为了捕获空指针的访问;
  5. PAGEZERO 的目的之二是为了隔绝 32 程序的运行;

3. 为什么64位系统的高16 位会被剪掉

32 位系统最大 CPU 最大寻址能力是 4GB,这已经有点不够用了,64位架构应运而生。

首先,64位系统的寻址能力是这么大:

64位地址范围

但是当前的电脑内存一般是 16~32GB,手机一般 2~16GB,所以使用 64位来寻址会造成:

  1. 硬件设计更复杂;
  2. 性价比不高;

虽然有些架构确实采用了 64 位寻址地址来进行设计和实现,如 SPARC 的 64 位版就允许完整的 64 位寻址空间,AArch64 允许用高 8 位来做tag,那么还有56 位寻址空间~~

但是主流的 64 位架构都是使用 48 位地址进行寻址,高 16 位做保留,这样做有几个好处:

  1. 性价比高;
  2. 以后逐步放开高 16 位即可兼容;
  3. 寻址设计相对简单(如 Page Table 的设计);

因此,48 位寻址的架构,其地址的范围就是 0~256TB,这在一段时间内已经很够用了。

另外需要注意一点:

  • 高16位必须是全1或全0,而且必须与低48位的最高位(第47位)一致;

设计为带符号扩展的原因也很简单:很多环境中,寻址空间的高一半(higher-half)有特殊用途,而低一半(lower-half)给用户做一般用途。这“高/低”可以通过最高位是1还是0来判断;如果把地址看成带符号整数,那么“负数”部分就是高一半,“正数”部分就是低一半。

维基百科:

维基百科


http://www.taodudu.cc/news/show-1912756.html

相关文章:

  • iOS图形学(三):屏幕成像原理
  • iOS图形学(四):iOS中的绘图框架
  • Java基础(一):简介和基础数据类型
  • Java基础(二):面向对象
  • Java:常量池
  • Java基础(三):常用对象
  • Java基础(四):异常处理
  • Java基础(五):多线程
  • Android:权限处理
  • AsyncTask的基本使用
  • 在Nginx中配置SSL证书
  • Base64编码流程
  • Nginx配置基础认证
  • Cookie、Session、Token、RefreshToken
  • JSCore浅析及其在iOS上的使用
  • 编程语言的动态性(Dart和OC对比)
  • iOS:Universal Link
  • AFN中的鉴权
  • openGL ES 教程(二):渲染管线
  • MySQL(2)----DDL语句之增、删、改、查操作
  • MySQL(3)-----DML数据库操作(上)
  • 线性表的基本运算
  • MySQL(4)-----DML数据库操作(下)
  • MySQL(1)----帮助使用
  • MySQL(6)-----数据类型
  • (1)封装JSON数据的三种方式
  • (2)从文件中解析JSON数据
  • (1)I/O流对象-----FileInputStream与FileOutputStream
  • MyBatis(一)------目录
  • MyBatis(二)------使用JDBC编程问题总结

iOS底层:PAGEZERO的作用相关推荐

  1. iOS底层原理探究 第一探. 事件传递和响应者链

    一. 声明:  本文意在探讨, 也参考了几位大神的文章, 在最后我会把链接发出来, 如果有理解错误的地方, 请大神们指正哈! 二. 前言:  最近自己做项目的时候, 用到了UITabbarContro ...

  2. iOS 底层探索篇 —— KVC 底层原理

    iOS 底层探索篇 -- KVC 底层原理 1. Method Swizzling的坑与应用 1.1 method-swizzling 是什么? 1.2 坑点 坑点1:method-swizzling ...

  3. 【iOS底层】11:消息转发

    一.msgSend消息发送监听 在探索了很多次了lookUpImpOrForward方法中,查找完成后会写入cache 在写入cache中发现有个打印log的操作 我们来看下是否可以通过这个输出到本地 ...

  4. iOS底层开发消息发送与转发流程

    iOS底层开发消息转发流程 一,cache缓存读取流程分析 首先我们上一章已经了解到对应的cache_t的数据结构 _bucketsAndMaybeMask:指针类型,存放buckets的首地址 _m ...

  5. iOS底层原理 - 常驻线程

    iOS底层原理 - 常驻线程 在 AFN 2.0 时代,会经常看到 AFN 创建一个常驻线程的方式: 0️⃣ AFN 2.0 时代的常驻线程 + (NSThread *)networkRequestT ...

  6. iOS底层探索(二) - 写给小白看的Clang编译过程原理

    iOS底层探索(一) - 从零开始认识Clang与LLVM 写在前面 编译器是属于底层知识,在日常开发中少有涉及,但在我的印象中,越接近底层是越需要编程基本功,也是越复杂的.但要想提升技术却始终绕不开 ...

  7. iOS底层原理之架构设计

    文章目录 何为架构? MVC - Apple版 MVC – 变种 MVP MVVM 设计模式 面试题 何为架构? 架构(Architecture):软件开发中的设计方案,类与类之间的关系.模块与模块之 ...

  8. iOS底层原理总结 - OC对象的本质

    苹果官方文档 The Objective-C language defers as many decisions as it can from compile time and link time t ...

  9. iOS底层原理之内存管理

    文章目录 定时器 CADisplayLink.NSTimer GCD定时器 内存管理 iOS程序的内存布局 Tagged Pointer OC对象的内存管理 拷贝 引用计数的存储 dealloc 自动 ...

  10. iOS 底层探索 - 消息转发

    一.动态方法解析流程分析 我们在上一章<消息查找>分析到了动态方法解析,为了更好的掌握具体的流程,我们接下来直接进行源码追踪. 我们先来到 _class_resolveMethod 方法, ...

最新文章

  1. TFS 无法签入或自动签出 解决方法 【强制撤销签出无效】
  2. 学习IOS开问题篇--视图的模型控件属性写在私有分类中的原因
  3. 订单可视化(智能制造、流程再造、企业信息化) 第五篇 团队建设
  4. 电商后台:实例解读订单系统
  5. Puppet dashboard安装
  6. tf.layers.dropout
  7. hdu 2544 最短路
  8. 8 SD配置-企业结构-分配-给公司代码分配销售组织
  9. 数据库期末复习知识点:(仅供参考)
  10. 适合本科生的AI比赛目录
  11. 在LINUX中部署FTP服务器
  12. DNS服务器构建(一)-—构建域名缓存服务器
  13. 怎么去掉字符串最后一个逗号
  14. 给Ubuntu 13.04换源 软件源、更新源
  15. 架构之美第十三章-美丽的架构
  16. sudo rosdep init 出现 ERROR: cannot download default sources list from:
  17. Unity 自定义扩展Hierachy右键菜单
  18. js父元素获取子元素img_js 下获取子元素的方法
  19. 锁定计算机后怎么解锁,电脑锁住了怎么解锁
  20. 安索夫矩阵分析市场和产品策略

热门文章

  1. Spring整合MyBatis之SqlSession对象的产生
  2. Mybatis使用技巧
  3. Jxl读写Excel文件
  4. Ubuntu学习 mkdir
  5. ibatis #于 $区别
  6. 浅谈Peer Review(同行评审)
  7. java模拟form表单提交图片文件
  8. 对Javascript异步执行的理解
  9. 【笔记】如何把GBK的文本格式转换为UTF-8格式
  10. 100个高质量Java开发者博客 【转】