为什么rsp寄存器从0x7FFFFFFFDD0开始

Isa*_*saí 3 linux assembly x86-64 stack-memory stack-pointer

我正在学习x86汇编,使用下面的代码进行测试,我在gdb控制台中看到指向堆栈顶部的rsp寄存器从0x7FFFFFFFDFD0开始,如果我理解正确的话,在代码中我没有使用push或pop修改 rsp,因此 0x7FFFFFFFDFD0 它是默认值,这意味着我们在堆栈中具有相同的字节数,但我使用堆栈大小为 8mb 的 Linux

section .text
global _start
_start:

mov rcx, 2
add rcx, 8

mov rax, 0x1
mov rbx, 0xff
int 0x80
Run Code Online (Sandbox Code Playgroud)

Bre*_*dan 8

对于 64 位 80x86;通常(参见注 1)只能使用 48 位虚拟地址。在不破坏旧软件的情况下,更容易增加未来处理器中可使用的位数;AMD 决定 64 位虚拟地址中未使用的最高 16 位应该匹配。符合此要求的地址称为“规范地址”,不符合此要求的地址称为“非规范地址”。通常(参见注释 2)任何尝试访问非规范地址处的任何内容都会导致异常(一般保护错误)。

这给出了一个虚拟地址空间,例如:

0x0000000000000000 to 0x00007FFFFFFFFFFF = canonical (often "user space")
0x0000800000000000 to 0xFFFF7FFFFFFFFFFF = non-canonical hole
0xFFFF800000000000 to 0xFFFFFFFFFFFFFFFF = canonical (often "kernel space")
Run Code Online (Sandbox Code Playgroud)

这使得相当明显的是,如果没有地址空间布局随机化,进程的初始线程堆栈(参见注释 3)会从略低于进程可以使用的最高地址的地址开始。

进程可以使用的最高地址与您看到的地址 (0x7FFFFFFFDFD0) 之间的差异仅为 2030 字节;它(正如 Fuz 的评论中提到的)被 ELF 辅助向量、命令行参数和环境变量等使用,它们在代码启动之前消耗部分堆栈。

注 1:Intel 最近(大约 2 年前?)创建了一个扩展(如果 CPU 和操作系统支持)使 57 位虚拟地址可用。在这种情况下,“非规范漏洞”缩小,进程可以使用的最高虚拟地址将增加到 0x00FFFFFFFFFFFFFF。

注 2:最近(大约 6 个月前?)Intel 创建了一个扩展(如果 CPU 和操作系统支持并为进程启用)可以使 CPU 忽略地址中未使用的高位;这样软件就可以将其他信息打包到这些位中(例如,可能是“数据类型”),而无需在使用前进行显式屏蔽。

注3:因为操作系统通常不提供线程之间的隔离(例如,任何线程都可以破坏任何其他线程的堆栈或任何其他线程的“线程本地数据”);如果您创建更多线程,它们将无法使用相同的“堆栈顶部”地址。