在Linux上使用RIP相对寻址的Segfault

我有一个简单的程序集代码,可以在Mac OS X(x86-64)上正常工作,但不能在Linux(x86-64)上运行:

.data .align 4 foo: .quad 1,2 .text .globl fun fun: movapd foo(%rip), %xmm1 ret 

从一个简单的C程序调用:

 int main(void){ fun(); return 0; } 

Mac上发生的事情是,xmm1寄存器填充了位于foo的数据,即在GDB中:

 (gdb) p $xmm1 $2 = { ... v2_int64 = {2, 1}, uint128 = 0x00000000000000020000000000000001 } 

当我在Linux下运行相同的代码它segfaults – 似乎foo标签对应于0x0:

 > objdump -d asm.o ... Disassembly of section .text: 0000000000000000 <fun>: 0: 66 0f 28 0d 00 00 00 movapd 0x0(%rip),%xmm1 ... 

有人可以解释为什么发生这种情况,我能做些什么来避免它?

干杯

  • 伊恩

在mainline gnu binutils上,在i386和x86_64上, .align n指令告诉汇编器对齐n个字节(然而,在一些架构和平台上,它还有其他含义,请查阅文档以获取全部细节)。

在OS X上, .align n指令告诉汇编器对齐2 ^ n个字节。 这就是为什么你的代码在Mac上工作。

如果您想要一致的跨平台行为,请改用两种平台上支持的.p2align指令,并告知汇编器对齐2 ^ n个字节。

段错误是由于错位而发生的。 一个4字节的队列对于movapd是不够的,你至少需要16个字节。至少16个字节。

您在objdump中看到0(%rip) ,因为代码尚未重定位。 运行时链接程序将在执行时用正确的偏移量替换它。