请注意,0x...865
and 0x...898
不是连续的,即使它们在问题中显示为一个没有空行的连续块的一部分。一个是另一个的分支目标。
它似乎正在检查一个可以适合 32 位 2 的补码整数的值,即在 INT32_MIN 和 INT32_MAX(包括)之间。像x == (int32_t)x
但是高半和低半的分支目标是不同的,否则它可以简单地movsxd rdx, eax
// cmp rax, rdx
。je
jnl
与 的条件相同jge
,因此它正在跳转(int64_t)rax >= INT_MIN
, INT_MIN 当然符号扩展为 64 位。
cmp rax, 0xffffffff80000000 # INT32_MIN
jge x_ge_INT32_MIN
# else fall-through: x < INT32_MIN
... other code here
x_ge_INT32_MIN:
cmp rax, 0x7fffffff # INT32_MAX
jle x_fits_in_int32_t
... else it doesn't, x > INT32_MAX
注意0xffffffff80000000
表示负符号整数,(int64_t)INT32_MIN
。这是 32-bit 的符号扩展0x80000000
。
我不知道是什么_M_extract_int()
,而且您没有链接任何 libstdc++ 源以获取使用信息。
我认为0xffffffff80000000是可以用于用户模式的顶级物理内存地址
不,0xffffffff80000000
位于虚拟地址空间的高半部分,因此还不算太高。有关x86-64 48 位规范虚拟地址空间的图表,请参阅地址规范形式和指针算法。
Linux(我认为所有主流的 x86-64 操作系统)保留整个上半部分供内核使用,用户空间能够在下半部分分配/映射页面。即用户空间可以使用整个低47位虚拟地址空间。(也许不是最底层,例如 Linux 默认停止进程映射低 64k,所以nullptr
取消引用,即使有偏移,仍然会出错。MacOS 保留整个低 4GiB。)
使用 5 级页表(Intel 的 PML5 扩展),用户空间可以使用 57 位虚拟地址空间的低 56 位。
无论哪种方式,这与此代码正在寻找的内容相似,但 48 或 57 位值正确符号扩展为 64 位,而不是 32 位。
身体的
不。libstdc++ 仅用于用户空间,因此它所看到的唯一地址是虚拟地址。