Reputation: 23
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 i.e. 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
Upvotes: 2
Views: 694
Reputation: 106117
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.
Upvotes: 3
Reputation: 30419
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.
Upvotes: 2