Преобразование [символ + константа] режима синтаксической адресации Intel в AT & T синтаксис? - PullRequest
0 голосов
/ 08 апреля 2020

Я просто не могу понять, как добавить смещение к месту назначения при перемещении значения, в частности, у меня есть синтаксис Intel:

MOV   [gdtr + 2], EAX

и для синтаксиса AT & T я попытался преобразовать его в:

movl %eax, gdtr(2,1)

, которая выдает ошибку при компиляции junk '(2,1)' after expression, но с использованием только gdtr(,1) работает нормально.

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

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

Просто напишите

movl %eax, gdtr+2

Адресация базового смещения работает только тогда, когда смещение является регистром. Нет смысла в режиме адресации добавлять две константы вместе; способ, которым это работает (независимо от синтаксиса), состоит в том, что ассемблер / компоновщик преобразует symbol+constant в одно число для поля смещения кодировки инструкции.

0 голосов
/ 08 апреля 2020

Это просто gdtr+2

gdtr(2,1) [выдает ошибку], но использование gdtr(,1) работает нормально.

Материал внутри () Парены в режиме адресации AT & T могут быть только регистрами (и масштабным коэффициентом): disp(base, index, scale). База и индекс необязательны, поэтому пусто - это хорошо, но недопустимо (не зарегистрировано) - нет.

И когда вы указываете шкалу без базы или индекса, очевидно, вы должны использовать только одну запятую: (,,1) является ошибкой относительно пустого масштабного коэффициента.
Вы можете написать его как gdtr+2(,1), чтобы явно не использовать регистры.

+2 является частью смещения в режиме адресации, а не регистры базы или индекса независимо от синтаксиса . См. Несколько вопросов о [base + index * scale + disp] или руководстве Intel или AMD о том, как кодируются режимы адресации. (То, что вы делаете, это режим адресации [disp32] или [disp16], с точки зрения того, как он будет закодирован в машинный код.)

Как указал Нейт, компоновщик позаботится о повороте сборки -временные литеральные константы + адреса константных символов времени связи в конечный адрес в машинном коде, закодированный как disp32 (или disp16 для 16-битного размера адреса). Или RIP-относительный rel32 для x86-64.

Интересный факт: некоторые сборщики AT & T принимают (gdtr) в качестве альтернативы gdtr, но не 2(gdtr).


Способы решить это самостоятельно:

Обычно, если вы застряли на NASM -> AT & T, вы можете собрать источник NASM (например, nasm -felf) и разобрать с помощью дизассемблера AT & T, например objdump -drwC. Но это не поможет здесь для символического c синтаксиса режима адресации, потому что в лучшем случае objdump -dr просто аннотирует числительные c режимы адресации с информацией об имени символа.

Так что в этом случае вам лучше всего получить G CC или clang для выдачи инструкции, которая использует имя символа и константу цифры c, например,

char gdtr[1024];                // global var so it has a symbol
char foo() { return gdtr[2]; }  // load from global symbol + constant.

компилируется с gcc9.3 -O2 -m32 в проводнике компилятора Godbolt к этому asm:

foo:
        movzbl  gdtr+2, %eax
        ret
gdtr:
        .zero   1024

Есть ваш режим адресации, и в качестве бонуса AT & T мнемони c для movzx с источником байтов. Конечно, вы можете поиграть с типами.

Компиляторы являются полезными ресурсами; они знают, как делать много вещей "обычным образом" при компиляции простых функций C, и они знают соглашение о вызовах и ширину типов. И AT & T синтаксис для всего, включая указатели функций. Если вы застряли, попросите компилятор . По сути, единственное, что вы не можете заставить показать компилятор, это синтаксис jmp far (AT & T ljmp)

...