简体   繁体   中英

Segfault with RIP-relative addressing on Linux

I have a simple piece of assembly code that works correctly on Mac OS X (x86-64) but not on Linux (x86-64):

.data
.align 4

foo: .quad 1,2

.text

.globl fun
fun:
movapd foo(%rip), %xmm1
ret

Called from a simple C program:

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

What happens on the Mac is that the xmm1 register is filled with the data at location foo ie in GDB:

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

When I run the same code under Linux it segfaults - it seems that the foo label corresponds to 0x0:

> objdump -d asm.o
...

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

Can someone explain why this occurs and what I can do to avoid it?

Cheers

  • Iain

The segfault happens because of misalignment. A 4 Byte alignment isn't sufficient for movapd, you need 16 Byte .align 16 at least.

You see 0(%rip) in objdump, because the code isn't relocated yet. The runtime linker will replace it with the correct offset when you execute it.

On the mainline gnu binutils, on i386 and x86_64, the .align n directive tells the assembler to align to n bytes (however, on some architectures and platforms, it has other meanings. Consult the documentation for full details).

On OS X, the .align n directive tells the assembler to align to 2^n bytes. This is why your code works on the Mac.

If you want consistent cross-platform behavior, use the .p2align directive instead, which is supported on both platforms, and tells the assembler to align to 2^n bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM