为什么这个 MOVSS 指令使用 RIP 相对寻址?

Why does this MOVSS instruction use RIP-relative addressing?

我在反汇编程序(浮点逻辑c++)中找到了以下汇编代码。

  842: movss  0x21a(%rip),%xmm0 

我知道当进程 rip 总是 842 时,这个 0x21a(%rip) 将是常量。使用这个寄存器似乎有点奇怪。

我想知道使用 rip 相对地址而不是其他地址有什么好处。

RIP是指令指针寄存器,也就是说它包含紧跟在当前指令之后的指令的地址。

例如,考虑以下代码:

mov  rax, [rip]
nop

在第一行代码中,RIP 指向 next 指令,因此它指向 NOP。因此,此代码将 NOP 指令的地址加载到 RAX 寄存器中。

因此,不是 RIP 只是一个常量的情况。您认为 RIP 在此过程中“将始终为 842”的理解是不正确的。 RIP 的值将根据代码加载到内存中的位置而改变。 842 只是行号,从您的调试符号中提取;一旦代码被编译成二进制文件,它就不再有行号了。 :-)

在您的反汇编中,常量是偏移量 (0x21A)。这是 RIP 中当前值的偏移量。另一种写法是:%rip + 0x21A.

RIP-相对寻址是64位长模式引入的一种新的有效寻址形式。关键是它使编写与位置无关的代码变得更容易,因为您可以使任何内存引用 RIP 相对。实际上,RIP-相对寻址是64位应用程序中默认的寻址方式。实际上 所有 在 64 位模式下寻址内存的指令都是 RIP 相对的。我会引用 Ken Johnson (aka Skywing)'s blog 因为我自己说得再好不过了:

One of the larger (but often overlooked) changes to x64 with respect to x86 is that most instructions that previously only referenced data via absolute addressing can now reference data via RIP-relative addressing.

RIP-relative addressing is a mode where an address reference is provided as a (signed) 32-bit displacement from the current instruction pointer. While this was typically only used on x86 for control transfer instructions (call, jmp, and soforth), x64 expands the use of instruction pointer relative addressing to cover a much larger set of instructions.

What’s the advantage of using RIP-relative addressing? Well, the main benefit is that it becomes much easier to generate position independent code, or code that does not depend on where it is loaded in memory. This is especially useful in today’s world of (relatively) self-contained modules (such as DLLs or EXEs) that contain both data (global variables) and the code that goes along with it. If one used flat addressing on x86, references to global variables typically required hardcoding the absolute address of the global in question, assuming the module loads at its preferred base address. If the module then could not be loaded at the preferred base address at runtime, the loader had to perform a set of base relocations that essentially rewrite all instructions that had an absolute address operand component to refer to take into account the new address of the module.

[ . . . ]

An instruction that uses RIP relative addressing, however, typically does not require any base relocations (otherwise known as “fixups”) at load time if the module containing it is relocated, however. This is because as long as portions of the module are not internally re-arranged in memory (something not supported by the PE format), any addresses reference that is both relative to the current instruction pointer and refers to a location within the confines of the current image will continue to refer to the correct location, no matter where the image is placed at load time.

As a result, many x64 images have a greatly reduced number of fixups, due to the fact that most operations can be performed in an RIP-relative fashion.

他是在 Windows 的上下文中发言,但概念上类似的东西也适用于其他操作系统。

您的代码正在将存储在二进制映像中某处的常量值加载到 XMM0 寄存器中,并且使用 RIP 相对寻址因为它有很多优点。