- 为什么不允许程序访问大于 0xc0000000 的地址,像 0xc0000008 这样的地址不是有效地址吗?
现代操作系统利用硬件的特性来防止正在运行的应用程序相互干扰。这种隔离的主要组成部分是权限分离和虚拟内存。
虚拟内存(相对于物理内存)意味着代码(例如mov
指令)访问的地址不是 RAM 的实际地址。相反,内存管理单元(MMU) 利用页表将虚拟地址 (VA)转换为物理地址 (PA),然后再将它们发送到 RAM。
权限分离由 CPU(和 MMU)强制执行,允许单个操作系统内核完全控制硬件,同时安全地运行多个用户应用程序。
将这两个概念放在一起,通常内核运行在虚拟内存的一个区域(用户空间无法访问),而用户空间进程运行在另一部分。
在 Linux 内核的 x86 32 位 arch 端口中,经常使用 1-3 拆分,为内核提供 1 GB 的 VA 空间,为每个用户应用程序留出 3 GB 的 VA 空间。因此:
- 0x00000000 - 0xBFFFFFFF:用户空间
- 0xC0000000 - 0xFFFFFFFF:内核
- 如果程序真的不允许访问大于 0xc0000000 的地址,0xfffffffc 小于(小于)0xc0000000,那为什么会失败呢?
数据的表示方式(例如在硬件寄存器或内存中)与数据的解释方式(例如有符号/无符号整数、浮点数、文本字符串、图像等)之间存在很大差异
请注意,如果将 0xFFFFFFFF解释为 32 位二进制补码(有符号)整数,则会得到 -1。如果将其解释为无符号整数,则得到 (2^32 - 1) = 4294967295。
地址总是无符号的;一般来说,当涉及到硬件时,没有负数。
0xFFFFFFFC 大于 0xC0000000。因此,这里它是一个内核地址,任何试图访问它的用户空间应用程序都会出错并被传递一个 SIGSEGV 信号。