0

嗨,我正在阅读一本教科书,它说程序不允许访问大于的地址0xc0000000(就像 32 位版本的 Linux 一样),所以下面的汇编代码是无效的:

1. irmovl $1,%eax
2. xorl %esp,%esp // Set stack pointer to 0 and CC to 100
3. pushl %eax    // Attempt to write to 0xfffffffc, will fail

我很困惑。我有两个问题:

  1. 为什么不允许程序访问大于 的地址0xc0000000,该地址不是0xc0000008有效地址吗?

  2. 如果程序真的不允许访问大于0xc0000000,0xfffffffc小于(小于) 的地址0xc0000000,那为什么会失败呢?

4

1 回答 1

5
  1. 为什么不允许程序访问大于 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:内核
  1. 如果程序真的不允许访问大于 0xc0000000 的地址,0xfffffffc 小于(小于)0xc0000000,那为什么会失败呢?

数据的表示方式(例如在硬件寄存器或内存中)与数据的解释方式(例如有符号/无符号整数、浮点数、文本字符串、图像等)之间存在很大差异

请注意,如果将 0xFFFFFFFF解释为 32 位二进制补码(有符号)整数,则会得到 -1。如果将其解释为无符号整数,则得到 (2^32 - 1) = 4294967295。

地址总是无符号的;一般来说,当涉及到硬件时,没有负数。

0xFFFFFFFC 大于 0xC0000000。因此,这里它是一个内核地址,任何试图访问它的用户空间应用程序都会出错并被传递一个 SIGSEGV 信号。

于 2018-10-11T12:38:20.627 回答