IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> iOS底层:PAGEZERO的作用 -> 正文阅读

[嵌入式]iOS底层:PAGEZERO的作用

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来判断;如果把地址看成带符号整数,那么“负数”部分就是高一半,“正数”部分就是低一半。

维基百科:

维基百科
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:23:50  更:2021-07-27 16:25:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:25:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计