Адресация памяти с помощью 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