Segfault с RIP-относительной адресацией в Linux - PullRequest
2 голосов
/ 07 февраля 2012

У меня есть простой фрагмент кода сборки, который корректно работает в 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
...

Может кто-нибудь объяснить, почему это происходит и что я могу сделать, чтобы избежать этого?

Cheers

  • Иан

Ответы [ 2 ]

2 голосов
/ 07 февраля 2012

Сегфоут происходит из-за смещения. 4-байтовое выравнивание недостаточно для movapd, вам нужно как минимум 16 байт .align 16.

Вы видите 0(%rip) в objdump, потому что код еще не перемещен. При запуске компоновщик заменит его на правильное смещение.

1 голос
/ 08 февраля 2012

В mainline gnu binutils, на i386 и x86_64, директива .align n указывает ассемблеру выравниваться на n байтов (однако на некоторых архитектурах и платформах это имеет другие значения. Для получения более подробной информации обратитесь к документации).

В OS X директива .align n указывает ассемблеру выравниваться по 2 ^ n байтов.Вот почему ваш код работает на Mac.

Если вы хотите согласованного кроссплатформенного поведения, вместо этого используйте директиву .p2align, которая поддерживается на обеих платформах и говорит ассемблеру выравниваться по 2 ^ nбайт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...