gpt4 book ai didi

x86-64 - 地址规范形式和指针算法

转载 作者:行者123 更新时间:2023-12-04 23:40:30 24 4
gpt4 key购买 nike

在 AMD64 兼容架构上,地址在被取消引用之前需要采用规范形式。

来自 Intel manual, section 3.3.7.1 :

In 64-bit mode, an address is considered to be in canonical form if address bits 63 through to the most-significant implemented bit by the microarchitecture are set to either all ones or all zeros.



现在,当前操作系统和架构上最重要的实现位是第 47 位。这给我们留下了一个 48 位的地址空间。

特别是当 ASLR启用时,用户程序可以期望接收设置了第 47 位的地址。

如果使用指针标记等优化并且使用高位来存储信息,则程序必须确保在取消引用地址之前将第 48 位到第 63 位设置回第 47 位。

但请考虑以下代码:
int main()
{
int* intArray = new int[100];

int* it = intArray;

// Fill the array with any value.
for (int i = 0; i < 100; i++)
{
*it = 20;
it++;
}

delete [] intArray;
return 0;
}

现在考虑 intArray就是说:

0000 0000 0000 0000 0 111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100

设置后 itintArray并增加 it一次,并考虑 sizeof(int) == 4 ,它将变成:

0000 0000 0000 0000 1 000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

第 47 位以粗体显示。这里发生的情况是,由指针算法检索到的第二个指针无效,因为不是规范形式。正确的地址应该是:

1111 1111 1111 1111 1 000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

程序如何处理这个问题?操作系统是否保证永远不会分配地址范围不随第 47 位变化的内存?

最佳答案

规范地址规则意味着 64 位虚拟地址空间中有一个巨大的漏洞。 2^47-1 与其上方的下一个有效地址不相邻,因此单个 mmap不会包含任何不可用的 64 位地址范围。

+----------+
| 2^64-1 | 0xffffffffffffffff
| ... |
| 2^64-2^47| 0xffff800000000000
+----------+
| |
| unusable | not to scale: this part is 2^16 times as large
| |
+----------+
| 2^47-1 | 0x00007fffffffffff
| ... |
| 0 | 0x0000000000000000
+----------+

还有大多数内核 reserve the high half供他们自己使用的规范范围。例如 x86-64 Linux's memory map .无论如何,用户空间只能在连续的低范围内分配,因此间隙的存在无关紧要。

Is there a guarantee by the OS that you will never be allocated memory whose address range does not vary by the 47th bit?



不完全是。当前硬件支持的 48 位地址空间是一个实现细节。规范地址规则确保 future 的系统可以支持更多的虚拟地址位,而不会严重破坏向后兼容性。

最多,您只需要一个 compat 标志即可让操作系统不为进程提供任何具有高位不完全相同的内存区域。 (就像 Linux 当前的 MAP_32BIT flag for mmap ,或进程范围的设置)。这可以支持使用高位作为标签并手动重新进行符号扩展的程序。

future 的硬件不需要支持任何类型的标志来忽略高地址位与否,因为高位中的垃圾当前是一个错误。 Intel 5-level paging添加了另外 9 个虚拟地址位,扩大了规范的高半和低半。 white paper .

另见 Why in 64bit the virtual address are 4 bits short (48bit long) compared with the physical address (52 bit long)?

有趣的事实:Linux 默认将堆栈映射到有效地址的较低范围的顶部。 (相关: Why does Linux favor 0x7f mappings?)
$ gdb /bin/ls
...
(gdb) b _start
Function "_start" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_start) pending.
(gdb) r
Starting program: /bin/ls

Breakpoint 1, 0x00007ffff7dd9cd0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) p $rsp
$1 = (void *) 0x7fffffffd850
(gdb) exit

$ calc
2^47-1
0x7fffffffffff

(现代 GDB 可以使用 starti 在第一条用户空间指令执行之前中断,而不是使用断点命令。)

关于x86-64 - 地址规范形式和指针算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38977755/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com