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