64 位或使用 64 位寄存器的地址大小覆盖前缀

Address-size override prefix in 64-bit or using 64-bit registers

在汇编寻址(64 位)中,哪种方式更好?

mov   cl, BYTE [ebx + .DATA]

mov   cl, BYTE [rbx + .DATA]

?

第一种方式的操作码是: 67 8a 4b .. 第二种方式的操作码是:8a 4b ..

所以如果我们使用 32 位寄存器,我们需要有一个 '0x67' 前缀(地址大小覆盖前缀)所以我认为我们添加了一个额外的工作!!!

但我听说了一些关于 (CACHE) 的事情,最好使用“32 位”而不是“64 位”

那么哪种方式更好呢?为什么?

TL:DR:您基本上不需要地址大小前缀。 使用 64 位寻址模式。

I heard something about (CACHE) and it's better to use '32-bit' instead of '64-bit'

您混淆了地址大小和操作数大小。 32 位整数占 space 的一半,因此更多的整数适合一个缓存行.更好的空间局部性,更少的内存带宽。

选择 64 位模式中的默认值是有原因的,并且是您在方便时应该更喜欢的,以便在其他条件相同的情况下节省代码大小():

  • 地址大小 = 64 位
  • 操作数大小 = 32 位

所以像 mov ecx, [rdi] 是最有效的情况;其他尺寸需要 REX 或其他前缀。字节操作数大小使用不同的操作码而不是前缀,但写入 8 位寄存器可能对完整寄存器的旧值有错误的依赖性。更喜欢movzx负载;对于 2 字节的操作码,这通常值得额外的代码大小字节。


如果您的号码正确地零扩展为 64 位,请避免使用地址大小前缀并使用

movzx ecx,  byte [rbx + .DATA]

写入 32 位位寄存器隐式零扩展到 64 位,因此您可以通过在内存中使用 32 位数据来节省缓存占用空间。

如果一个索引可能不能被正确地零扩展或符号扩展到地址大小,您可能需要一个额外的指令来实现这一点(movsxd rcx, ebxmov ecx, ebx) 所以你可以使用 64 位寻址模式。

[reg + sign_extended_disp32] 寻址模式是一个有趣的案例:它们仅适用于所有适合 32 位的符号地址。如果您知道整个数组位于虚拟地址 space 的低 4GiB 中,您可能会使用 [ebx + .DATA] 以避免额外的指令扩展到 64 位,如果您知道可能存在垃圾在 RBX 的上半部分。 (所以 user-space 中的静态地址,但可能不在 high-half 内核中,你可能在 64 位虚拟地址的 high 32 位中有静态数据space.)


如果您知道您的指针可以安全地截断为 32 位(例如 mmap(MAP_32BIT) 或使用 x32 ABI),您甚至可以使用像 [=] 这样的指令遍历链表或树18=] 循环。可能对指针密集型数据结构有用。

(您的问题是关于数组索引,而不是指针;在 asm 中,您通常希望将它们视为 32 位无符号整数,如果数组可以很大,则为 64。 或者使用指针而不是 [reg+disp32] 来遍历数组; disp32 绝对地址仅适用于 Linux 位置相关的可执行文件,或 Windows LARGEADDRESSAWARE=no.)