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

时间:2017-07-07 09:18:59

标签: assembly x86 x86-64 disassembly addressing-mode

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

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

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

我想知道使用rip相对地址是否有任何优势,而不是其他寻址。

1 个答案:

答案 0 :(得分:4)

RIP是指令指针寄存器,这意味着它包含紧跟在当前指令之后的指令的地址。

例如,请考虑以下代码:

mov  rax, [rip]
nop

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

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

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

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

  

x64相对于x86的一个较大(但经常被忽视)的变化是,以前仅通过绝对寻址引用数据的大多数指令现在可以通过 RIP相对寻址来引用数据。

     

RIP相对寻址是一种模式,其中地址引用作为当前指令指针的(带符号)32位位移提供。虽然这通常仅在x86上用于控制传输指令(call,jmp和soforth),但x64扩展了指令指针相对寻址的使用,以覆盖更大的指令集。

     

使用RIP相对寻址有什么好处?好吧,主要好处是生成位置无关代码或者不依赖于它在内存中加载位置的代码变得容易得多。这在包含数据(全局变量)和随之而来的代码的(相对)自包含模块(例如DLL或EXE)的今天是特别有用的。如果在x86上使用平面寻址,则对全局变量的引用通常需要对所讨论的全局的绝对地址进行硬编码,假设模块加载在其首选基址上。如果在运行时无法将模块加载到首选基址,则加载器必须执行一组基址重定位,它基本上重写了具有要引用的绝对地址操作数组件的所有指令。记帐模块的新地址。

     

[。 。 。 ]

     

但是,使用RIP相对寻址的指令通常在加载时不需要任何基址重定位(也称为“fixups”),但是如果重定位包含它的模块。这是因为只要模块的某些部分没有在内部重新排列在内存中(PE格式不支持的内容),任何地址都会引用相对于当前指令指针的地址,并引用该范围内的位置。无论图像在加载时放置在何处,当前图像都将继续指向正确的位置。

     

因此,许多x64图像的修正次数大大减少,因为大多数操作都可以以RIP相对的方式执行。

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

您所拥有的代码是将一个存储在二进制映像中某处的常量值加载到XMM0寄存器中,并且由于它具有许多优点,因此使用RIP相对寻址。