Как работают относительные переменные RIP, такие как «[RIP + _a]» в x86-64 GAS Intel-синтаксис? - PullRequest
0 голосов
/ 18 февраля 2019

Рассмотрим следующую ссылку на переменную в сборке Intel x64, где переменная a объявлена ​​в разделе .data:

mov eax, dword ptr [rip + _a]

Мне трудно понять, как работает эта ссылка на переменную.Поскольку a является символом, соответствующим адресу времени выполнения переменной (с перемещением), как [rip + _a] может разыменовать правильную ячейку памяти a?Действительно, rip содержит адрес текущей инструкции, который является большим положительным целым числом, поэтому добавление приводит к неправильному адресу a?

И наоборот, если я использую синтаксис x86 (который оченьинтуитивно понятно:

mov eax, dword ptr [_a]

, я получаю следующую ошибку: 32-разрядная абсолютная адресация не поддерживается в 64-разрядном режиме .

Любое объяснение?

  1 int a = 5;
  2 
  3 int main() {
  4     int b = a;
  5     return b;
  6 }   

Компиляция: gcc -S -masm=intel abs_ref.c -o abs_ref:

  1     .section    __TEXT,__text,regular,pure_instructions
  2     .build_version macos, 10, 14
  3     .intel_syntax noprefix
  4     .globl  _main                   ## -- Begin function main
  5     .p2align    4, 0x90
  6 _main:                                  ## @main
  7     .cfi_startproc
  8 ## %bb.0:
  9     push    rbp
 10     .cfi_def_cfa_offset 16
 11     .cfi_offset rbp, -16
 12     mov rbp, rsp
 13     .cfi_def_cfa_register rbp
 14     mov dword ptr [rbp - 4], 0
 15     mov eax, dword ptr [rip + _a]
 16     mov dword ptr [rbp - 8], eax
 17     mov eax, dword ptr [rbp - 8]
 18     pop rbp
 19     ret
 20     .cfi_endproc
 21                                         ## -- End function
 22     .section    __DATA,__data
 23     .globl  _a                      ## @a
 24     .p2align    2
 25 _a:
 26     .long   5                       ## 0x5
 27 
 28 
 29 .subsections_via_symbols

1 Ответ

0 голосов
/ 18 февраля 2019

Синтаксис GAS для относительной RIP-адресации выглядит как symbol + RIP, но на самом деле это означает symbol относительно RIP.

несовместимость с числовыми литералами:

  • [rip + 10] или AT & T 10(%rip) означает 10 байтов после конца этой инструкции
  • [rip + a] или AT & T a(%rip) означает вычисление rel32 смещение для достижения a, не RIP + значение символа.
  • [a] или AT & T a - абсолютный адрес, использующий режим адресации disp32.Это не поддерживается в OS X, где базовый адрес образа всегда находится за пределами младших 32 бит.(Или для mov в al / ax / eax / rax, возможно 64-битное абсолютное кодирование moffs, но вы этого не хотите). Невозможно переместить переменные в .data в регистры с помощью сборки Mac x86 .

    Позиционно-зависимые исполняемые файлы Linux do поместить статический код / ​​данные в младшие 31 бит виртуальной памяти.адресное пространство, поэтому вы можете / должны использовать mov edi, sym там, но в OS X ваш лучший вариант - lea rdi, [sym+RIP], если вам нужен адрес в реестре.

(в OS Xсоглашение гласит, что в именах переменных / функций языка C в asm добавляется _. В написанном от руки asm у вас нет , чтобы сделать это для символов, к которым вы не хотите обращаться из C.)


NASM гораздо менее запутан в этом отношении:

  • [rel a] означает относительную RIP-адресацию для [a]
  • [abs a] означает[disp32].
  • default rel или default abs устанавливает, что используется для [a].По умолчанию (к сожалению) default abs, поэтому вам почти всегда нужен default rel.

Пример с .set значениями символов и меткой

.intel_syntax noprefix
mov  dword ptr [sym + rip], 0x11111111
sym:

.equ x, 8 
inc  byte ptr [x + rip]

.set y, 32 
inc byte ptr [y + rip]

.set z, sym
inc byte ptr [z + rip]

gcc -nostdlib foo.s && objdump -drwC -Mintel a.out (в Linux; у меня нет OS X):

0000000000001000 <sym-0xa>:
    1000:       c7 05 00 00 00 00 11 11 11 11   mov    DWORD PTR [rip+0x0],0x11111111        # 100a <sym>    # rel32 = 0; it's from the end of the instruction not the end of the rel32 or anywhere else.

000000000000100a <sym>:
    100a:       fe 05 08 00 00 00       inc    BYTE PTR [rip+0x8]        # 1018 <sym+0xe>
    1010:       fe 05 20 00 00 00       inc    BYTE PTR [rip+0x20]        # 1036 <sym+0x2c>
    1016:       fe 05 ee ff ff ff       inc    BYTE PTR [rip+0xffffffffffffffee]        # 100a <sym>

(Разборка .o с objdump -dr покажет вам, что нет никаких перемещений для компоновщикачтобы заполнить, все они были сделаны во время сборки.)

Обратите внимание, что только .set z, sym привело к вычислению по отношению к.x и y были оригинальными из простых числовых литералов, а не меток, поэтому, хотя сама инструкция использовала [x + RIP], мы все равно получили [RIP + 8].


(только для Linux без PIE)): По адресу абсолютный 8 относительноRIP, вам понадобится AT & T синтаксис incb 8-.(%rip).Я не знаю, как написать это в ГАЗ intel_syntax;[8 - . + RIP] отклоняется с Error: invalid operands (*ABS* and .text sections) for '-'.

Конечно, вы все равно не можете сделать это в OS X, за исключением, может быть, абсолютных адресов, которые находятся в диапазоне базы изображений.Но, вероятно, нет перемещения, которое могло бы содержать 64-битный абсолютный адрес для расчета для 32-битного rel32.

...