考虑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
答案 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 rel
或default 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>
(将.o
与objdump -dr
进行反汇编将显示您没有任何可用于链接器填充的重定位,它们都是在组装时完成的。)
请注意,只有.set z, sym
会进行尊重度计算。 x
和y
源自普通数字文字,而不是标签,因此即使指令本身使用了[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位绝对地址。