842: movss 0x21a(%rip),%xmm0
我理解当进程rip时,始终会是842,并且这个0x21a(%rip)将是常量。使用这个寄存器似乎有点奇怪。
我想知道使用rip相对地址是否有任何优势,而不是其他寻址方式。
842: movss 0x21a(%rip),%xmm0
我理解当进程rip时,始终会是842,并且这个0x21a(%rip)将是常量。使用这个寄存器似乎有点奇怪。
我想知道使用rip相对地址是否有任何优势,而不是其他寻址方式。
RIP
是指令指针寄存器,这意味着它包含当前指令后紧随其后的指令地址。
例如,考虑以下代码:
mov rax, [rip]
nop
在这段代码的第一行中,RIP
指向下一条指令,所以它指向了NOP
。因此,这段代码将NOP
指令的地址加载到了RAX
寄存器中。
因此,RIP
并不是一个简单的常量。你认为这个过程中RIP
“总是会是842”是不正确的。RIP
的值将根据代码被加载到内存的位置而改变。842只是从调试符号中提取的行号;一旦代码被编译成二进制文件,就不再有行号了。:-)
在你的反汇编中,常量是偏移量(0x21A
)。这是相对于RIP
当前值的偏移量。另一种写法是:%rip + 0x21A
。
RIP
相对寻址是64位长模式引入的一种新型有效寻址形式。其意义在于,通过使用RIP
相对寻址,可以更容易地编写位置无关代码,因为可以使任何内存引用都是RIP
相对的。事实上,在64位应用程序中,RIP
相对寻址是默认的寻址模式。在64位模式下几乎所有访问内存的指令都是RIP
相对的。我会引用Ken Johnson (aka Skywing)的博客,因为我无法更好地表述:
关于x64与x86之间的较大(但经常被忽视的)变化之一是,现在大多数先前只通过绝对寻址引用数据的指令现在都可以通过RIP相对寻址引用数据。
RIP相对寻址是一种地址参考,它以当前指令指针为基础提供一个(有符号的)32位位移量。虽然在x86上通常只在控制转移指令(call、jmp等)中使用这个指令指针寄存器相对寻址,但x64将指令指针寄存器相对寻址的使用扩展到了覆盖更广泛的指令集。
使用RIP相对寻址的优点是什么呢?主要好处是,生成位置无关代码变得更加容易,或者说代码不依赖于其在内存中加载的位置。在今天的(相对)自包含模块(例如DLL或EXE)中同时包含数据(全局变量)和相应代码的情况下,这一点尤其有用。如果在x86上使用平面寻址,则对全局变量的引用通常需要硬编码该全局变量的绝对地址,假设模块在其首选基地址处被加载。如果在运行时不能将模块加载到首选基地址,则加载程序必须执行一组基地址重定位,以实际重写所有具有绝对地址操作数部分的指令,以反映模块的新地址。
[ . . . ]
但是,使用RIP相对寻址的指令通常不需要任何基地址重定位(也称为“修复”),即使包含它的模块被重新定
mov rax, moffs64
(A1
)和mov moffs64, rax
(A3
)。我认为,RIP相对寻址的引入是为了避免使用64位立即数,而不是为了追求PIC,这只是一个副作用。毕竟,在RISC中也是通过这种方式解决了这个问题。然而,这只是我的个人看法。 - Margaret Bloom