Указание 8-битного немедленного в x86-64 (GNU Assembler)
Я пытаюсь написать некоторую специальную подпрограмму на ассемблере, для x86-64 (даже пример x86 подойдет) Проблема: мои немедленные решения разрешаются только во время ссылки.
Например,
addq $Label2-Label1, %rax
добавит разницу между двумя метками / символами в rax. К сожалению, поскольку GNU Assembler делает только один проход (я не знаю почему, даже ассемблеры с открытым исходным кодом, такие как FASM, делают несколько проходов), он не может разрешить их, поэтому компоновщик сделает это.
К сожалению, он зарезервирует 4 байта (32-битный немедленный) для компоновщика, а это не то, чего я хочу, потому что разница в метках всегда находится в диапазоне от -128 до +127.
Мой вопрос, как мне принудительно указать или указать, что инструкция должна иметь немедленное 8-битное значение? Мол, какой тут синтаксис? В AT&T синтаксис или Intel, либо хорошо. Например, в NASM вы делаете:
add rax, byte Label2-Label1
указать 8bit немедленно. Но как это сделать в ГАЗЕ? Какой синтаксис заставляет его использовать 8-битный немедленный, даже если он не знает самого непосредственного... В идеале я бы хотел, чтобы это было в GAS, поэтому, пожалуйста, не говорите мне использовать NASM как ответ!
РЕДАКТИРОВАТЬ: Извините, я забыл упомянуть, что да, это "прямая ссылка" здесь. Обе метки определены после инструкции, поэтому GAS не может их разрешить, я подумал, что это перемещение, но да, использование ".byte label2-label1" работает точно, так как я его протестировал, поэтому я знаю, что это должно быть возможно если бы у него был какой-то синтаксис для него...
2 ответа
Если Label1
а также Label2
находятся в том же исходном файле, то проблема, похоже, не связана с компоновщиком (в этом случае GAS не генерирует никаких перемещений), а также не потому, что GAS является однопроходным ассемблером. Он достаточно умен, чтобы генерировать ветви правильного размера, что является аналогичной проблемой.
Проблема сводится к тому, что GAS недостаточно умен, чтобы выбрать правильную команду размера в случаях, отличных от переходов и переходов, и не имеет возможности явно указать размер операнда. Суффикс смещения ".d8" - это почти тот синтаксис, который вам нужен, но технически вы не используете смещение. Но это не сработает, так как leal.d8 Label2-Label1(%eax),%eax
не работает, несмотря на то, что смещение фактически используется.
Так что на самом деле остается только одна альтернатива - ручная сборка кода операции. Например в 32-битной сборке:
.byte 0x83, 0xC0, (label2 - label1)
Что касается того, почему GAS является только однопроходным ассемблером, и, в общем, не делает ряд вещей другими ассемблерами, ответ прост. Он в первую очередь предназначен для сборки выходных данных GCC.
К сожалению, это невозможно; поскольку GAS не определяет, какая должна быть разница, у него нет другого выбора, кроме как оставить 4-байтовую запись перемещения для разрешения компоновщиком. Это связано с тем, что формат объектного файла (более чем вероятный ELF) не поддерживает 8-разрядные перемещения - он поддерживает только 32-разрядные перемещения. Таким образом, он всегда будет использовать 32-битный немедленный.