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

时间:2012-02-07 13:50:27

标签: linux macos assembly

我有一段简单的汇编代码可以在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下运行相同的代码时会出现段错误 - 似乎foo标签对应于0x0:

> objdump -d asm.o
...

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

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

干杯

  • 伊恩

2 个答案:

答案 0 :(得分:2)

由于未对齐而发生了段错误。对于movapd,4字节对齐是不够的,至少需要16个字节.align 16

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

答案 1 :(得分:1)

在主线gnu binutils上,在i386和x86_64上,.align n指令告诉汇编器对齐n个字节(但是,在某些体系结构和平台上,它有其他含义。请参阅文档以获取完整的详细信息)

在OS X上,.align n指令告诉汇编器对齐2 ^ n个字节。这就是您的代码在Mac上运行的原因。

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