x86-64 GAS Intel语法中的RIP相对变量引用(例如“ [RIP + _a]”)如何工作?

时间:2019-02-18 11:07:11

标签: assembly x86 x86-64 gas intel-syntax

考虑x64 Intel程序集中的以下变量引用,其中a部分中声明了变量.data

mov eax, dword ptr [rip + _a]

我很难理解此变量引用的工作方式。由于a是与变量的运行时地址相对应的符号(具有重定位),因此[rip + _a]如何解除对a的正确存储位置的引用?确实,rip持有当前指令的地址,它是一个大的正整数,因此加法会导致错误的a地址?

相反,如果我使用x86语法(非常直观):

mov eax, dword ptr [_a]

,出现以下错误: 64位模式不支持32位绝对寻址

有什么解释吗?

  1 int a = 5;
  2 
  3 int main() {
  4     int b = a;
  5     return b;
  6 }   

编译:{{1​​}}:

gcc -S -masm=intel abs_ref.c -o abs_ref

1 个答案:

答案 0 :(得分:1)

用于RIP相对寻址的GAS语法看起来像symbol + RIP,但实际上对于 symbol 来说是 RIP

数字文字不一致:

  • [rip + 10]或AT&T 10(%rip)表示该指令末尾的10个字节
  • [rip + a]或AT&T a(%rip)表示要计算rel32位移以达到a不是 RIP +符号值。
  • [a]或AT&T a是绝对地址,使用disp32寻址模式。 OS X不支持此功能,因为OS X的图像基址始终在低32位之外。 (或者对于mov到al / ax / eax / rax,可能是64位绝对moffs编码,但您不希望这样)。 Unable to move variables in .data to registers with Mac x86 Assembly

    Linux位置相关的可执行文件 do 将静态代码/数据放在虚拟地址空间的低31位中,因此您可以/应该在其中使用mov edi, sym,但是最好在OS X上使用如果您需要寄存器中的地址,则选项为lea rdi, [sym+RIP]

(在OS X中,惯例是C变量/函数名称在asm中以_开头。在手写asm中,您没有对此符号执行此操作您不想从C进行访问。)


NASM在这方面的困惑要小得多:

  • [rel a]表示[a]的RIP相对寻址
  • [abs a]的意思是[disp32]
  • default reldefault abs设置[a]使用的内容。默认情况下(不幸的是)是default abs,因此您几乎总是想要一个default rel

带有.set符号值和标签的示例

.intel_syntax noprefix
mov  dword ptr [sym + rip], 0x11111111
sym:

.equ x, 8 
inc  byte ptr [x + rip]

.set y, 32 
inc byte ptr [y + rip]

.set z, sym
inc byte ptr [z + rip]

gcc -nostdlib foo.s && objdump -drwC -Mintel a.out(在Linux上;我没有OS X):

0000000000001000 <sym-0xa>:
    1000:       c7 05 00 00 00 00 11 11 11 11   mov    DWORD PTR [rip+0x0],0x11111111        # 100a <sym>    # rel32 = 0; it's from the end of the instruction not the end of the rel32 or anywhere else.

000000000000100a <sym>:
    100a:       fe 05 08 00 00 00       inc    BYTE PTR [rip+0x8]        # 1018 <sym+0xe>
    1010:       fe 05 20 00 00 00       inc    BYTE PTR [rip+0x20]        # 1036 <sym+0x2c>
    1016:       fe 05 ee ff ff ff       inc    BYTE PTR [rip+0xffffffffffffffee]        # 100a <sym>

(将.oobjdump -dr进行反汇编将显示您没有任何可用于链接器填充的重定位,它们都是在组装时完成的。)

请注意,只有.set z, sym会进行尊重度计算。 xy源自普通数字文字,而不是标签,因此即使指令本身使用了[x + RIP],我们仍然得到[RIP + 8]


(仅适用于Linux非PIE):解决绝对8问题。 RIP,您需要AT&T语法incb 8-.(%rip)。我不知道如何在GAS intel_syntax中编写该代码; [8 - . + RIP]Error: invalid operands (*ABS* and .text sections) for '-'拒绝。

当然,除了在映像库范围内的绝对地址外,您都无法在OS X上执行此操作。但是可能没有重定位可以容纳要为32位rel32计算的64位绝对地址。