Адресация памяти с помощью GNU Assember Intel Syntax

Я прочитал эту страницу, содержащую хороший список различий между синтаксисом Intel и AT&T для GAS, но он не охватывал случай указания адреса только смещением.

Здесь я собрал четыре строки с синтаксисом AT&T:

                         .text
0000 48C7C008000000      mov    $8, %rax
0007 488B042508000000    mov    (8), %rax
000f 4889F0              mov    %rsi, %rax
0012 488B06              mov    (%rsi), %rax

Первые две строки отличаются, как и ожидалось. Первый перемещает непосредственное значение 8 в rax, а второй перемещает содержимое адреса 8 в rax. Но с синтаксисом Intel я получаю следующее странное поведение:

                         .text
                         .intel_syntax
0000 48C7C008000000      mov    %rax, 8
0007 48C7C008000000      mov    %rax, [8]
000e 4889F0              mov    %rax, %rsi
0011 488B06              mov    %rax, [%rsi]

Здесь первая и вторая строки собраны в один и тот же машинный код! Сначала я подумал, что квадратные скобки были неправильными, поэтому я добавил третью и четвертую строки в тест, и квадратные скобки работают для адресации памяти, по крайней мере, когда речь идет о регистрах.

Вся прочитанная мною документация показывает примеры адресации памяти, по крайней мере, с базовым или индексным регистром, а иногда с масштабом и смещением, но не только смещением.

У меня есть опыт работы с синтаксисом Intel с использованием ассемблера NASM, который отличает mov rax, 8 а также mov rax, [8],

Это ошибка в газе? Или, если нет, как мне указать эквивалент NASM mov rax, [8]?

Я понимаю, что, вероятно, редко указывается адрес только для смещения, но я хотел бы получить полное понимание всех форм адресации памяти с этим синтаксисом.

2 ответа

Решение

Был действительно такой баг в gas - см. http://sourceware.org/bugzilla/show_bug.cgi?id=10637.

Похоже, что это исправлено в (или, возможно, раньше) binutils 2.21.51.

Вы видите особый случай синтаксиса AT&T здесь. Обычно для адресных операндов у вас есть:

<op> [ src, ] displacement(base,index,scale) [, tgt ]

Любые составляющие операнда адреса в синтаксисе AT&T являются необязательными, поэтому вы можете написать mov (%rax, %rbx), ... или же mov 0(%rax, %rbx, 1), ... или любая другая такая комбинация.

Внутри () в скобках единственное число, которое вы обычно можете иметь, - это масштабный коэффициент (если имеется).

Но ассемблер также принимает (и создает идентичный код для):

mov <absolute>, ...
mov (<absolute>), ...

Это работает, только если операнд внутри () это простой номер / абсолютный адрес, иначе ассемблер жалуется, что то, что вы дали, не является допустимым масштабным коэффициентом. Эта эквивалентность является частным случаем в синтаксисе AT&T - я не уверен, почему это было / разрешено.

Использование $ однако в синтаксисе AT&T всегда указывается константа, а не адресный операнд, который совпадает с пустым числом в синтаксисе Intel.

Следующее иллюстрирует эквивалентность:

$ cat t.s
        mov     (8), %rax
        mov     $8, %rax
        mov     8, %rax
.intel_syntax
        mov %rax, [ 8 ]
        mov %rax, 8
        mov %rax, %ds:8

$ objdump -w -d t.o

t.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
   8:   48 c7 c0 08 00 00 00            mov    $0x8,%rax
   f:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  17:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  1f:   48 c7 c0 08 00 00 00            mov    $0x8,%rax
  26:   48 8b 04 25 08 00 00 00         mov    0x8,%rax

$ objdump -w -M intel -d t.o

t.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 :
   0:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8
   8:   48 c7 c0 08 00 00 00            mov    rax,0x8
   f:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8
  17:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  1f:   48 c7 c0 08 00 00 00            mov    rax,0x8
  26:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8
Другие вопросы по тегам