需要理解0x7fffffff和0xfffffff80000000在内存地址space布局方面的含义

needs to understand the meaning behind 0x7fffffff and 0xffffffff80000000 in terms of memory address space layout

# 0x00007f33caf5a85f: cmp rax, 0xffffffff80000000
# 0x00007f33caf5a865: jnl 0x7f33caf5a898
...
target_of_jnl:
# 0x00007f33caf5a898: cmp rax, 0x7fffffff
# 0x00007f33caf5a89e: jle 0x7f33caf5a8c8

以上代码片段是 libstdc++ 中函数 _M_extract_int() 执行流程的一部分。

我不明白这两个比较的意思。我认为 0xffffffff80000000 是可用于用户模式的顶级物理内存地址。但是 0x7fffffff 呢?他们在检查什么?

请注意,0x...8650x...898 不是连续的,即使它们在问题中显示为一个没有空行的连续块的一部分。一个是另一个的分支目标。

它似乎在检查一个值是否适合 32 位 2 的补码整数,即在 INT32_MIN 和 INT32_MAX 之间(含).喜欢x == (int32_t)x

但是high-half和low-half的分支目标是不同的,否则它可以简单地movsxd rdx, eax / cmp rax, rdx / je.

jnl is the same condition as jge,所以它跳到 (int64_t)rax >= INT_MIN,INT_MIN 当然 sign-extended 到 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位0x80000000的sign-extension.


我不知道 _M_extract_int() 是做什么的,而且您没有 link 任何 libstdc++ 源以获取使用信息。


I think 0xffffffff80000000 is the top physical memory address can be used for user mode

不,0xffffffff80000000 位于虚拟地址 space 的高半部分,因此还不算太高。有关 x86-64 48 位规范虚拟 address-space 的图表,请参阅

Linux(我认为所有主流 x86-64 操作系统)保留整个上半部分供内核使用,user-space 能够在下半部分分配/映射页面。即user-space可以使用虚拟地址的整个低47位space。 (也许不是最底层,例如 Linux 默认情况下停止进程映射低 64k,因此 nullptr 取消引用,即使有偏移,仍然会出错。MacOS 保留整个低 4GiB。)

有了5级页表(Intel的PML5扩展),user-space可以使用57位虚拟地址的低56位space。

无论哪种方式,这都与此代码正在寻找的东西类似,但是 48 或 57 位值正确地 sign-extended 到 64 位,而不是 32 位。

physical

不。 libstdc++ 仅在 user-space 中使用,因此它看到的唯一地址是虚拟地址。