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



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

mov   cl, BYTE [ebx + .DATA]

mov   cl, BYTE [rbx + .DATA]

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

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

但我听说过一些关于(CACHE(的事情,最好使用"32 位"而不是"64 位">

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

TL:DR:你基本上从不想要地址大小的前缀。使用 64 位寻址模式。

我听说过一些关于(CACHE(的信息,最好使用"32位"而不是"64位">

您将地址大小与操作数大小混为一谈。32 位整数占用一半的空间,因此更多的整数可以放在一个缓存行中。 更好的空间局部性,更少的内存带宽。

选择 64 位模式下的默认值是有原因的,并且是您在方便时应该更喜欢的,以便在其他条件相同时保存代码大小(在 x86-64 中使用 32 位寄存器/指令的优点(:

  • 地址大小 = 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 位的所有符号地址。 如果您知道整个阵列位于虚拟地址空间的低 4GiB 中,如果您知道 RBX 的高半部分可能有垃圾,您可能会[ebx + .DATA]避免额外的指令扩展到 64 位。 (因此,用户空间中的静态地址,但可能不在高半内核中,在高半核中,您可能在 64 位虚拟地址空间的高 32 位中具有静态数据。


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

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

最新更新