НАСМ против ГАЗА (Практические отличия)

Я не пытаюсь подсказать войну Intel против AT&T (во всяком случае, теперь, когда они оба поддерживают синтаксис Intel) или спрашивать, какой из них "лучше" сам по себе, я просто хочу знать практические различия в выборе одного или другого,

По сути, когда я несколько лет назад собирал какую-то базовую сборку x86, я использовал NASM не по какой-либо другой причине, кроме книги, которую я тоже читал - что твердо, но невольно поставило меня в лагерь NASM. С тех пор у меня было очень мало причин использовать сборку, поэтому у меня не было возможности попробовать GAS.

Принимая во внимание, что они оба поддерживают синтаксис Intel (который я лично предпочитаю) и должны, по крайней мере теоретически, создавать один и тот же двоичный файл (я знаю, что они, вероятно, не будут, но значение не должно быть изменено), каковы причины для предпочтения один или другой?

Это параметры командной строки? Макросы? Не мнемонические ключевые слова? Или что-то другое?

Спасибо:)

5 ответов

NASM фактически использует свой собственный вариант синтаксиса Intel, отличный от синтаксиса MASM, используемого в официальной документации Intel. Имена кодов операций и порядок операндов такие же, как в Intel, поэтому инструкции выглядят одинаково на первый взгляд, но любая значимая программа будет иметь различия. Например, с MASM инструкция используется MOV ax, foo зависит от типа fooв то время как NASM не имеет типов, и это всегда собирает немедленную инструкцию. Когда размер операнда не может быть определен неявно, MASM требует что-то вроде DWORD PTR для использования там, где используется NASM DWORD означать то же самое. Большая часть синтаксиса, кроме мнемоники инструкций и основного формата и порядка операндов, отличается.

С точки зрения функциональности NASM и GAS практически одинаковы. Оба имеют макро-ассемблерные средства, хотя NASM более обширный и более зрелый. Многие файлы исходного кода GAS используют препроцессор C вместо собственной поддержки макроса GAS.

Эта самая большая разница между двумя ассемблерами заключается в их поддержке 16-битного кода. GAS не поддерживает определение сегментов x86. С помощью GAS вы можете создавать простые односегментные 16-разрядные двоичные образы, в основном просто загрузочные сектора и файлы.COM. NASM полностью поддерживает сегменты и поддерживает объектные файлы формата OMF, которые можно использовать с подходящим компоновщиком для создания сегментированных 16-битных исполняемых файлов.

В дополнение к формату объектных файлов OMF NASM поддерживает ряд форматов, которые GAS не поддерживает. Обычно GAS поддерживает только собственный формат для машины, на которой он работает, в основном ELF, PE-COFF или MACH-O. Если вы хотите поддерживать другой формат, вам нужно создать кросс-компилируемую версию GAS для этого формата.

Еще одно заметное отличие заключается в том, что GAS поддерживает создание DWARF и 64-разрядную информацию о развертывании в Windows (позднее это требуется для Windows x64 ABI), в то время как с помощью NASM вы создаете разделы и заполняете данные самостоятельно.

Синтаксис Intel: mov eax, 1 (назначение инструкции, источник)

Синтаксис AT&T: movl $1, %eax (источник инструкции, место назначения)

Синтаксис Intel довольно понятен. В приведенном выше примере количество данных, которые перемещаются, определяется из размера регистра (32 бита в случае eax). Используемый режим адресации выводится из самих операндов.

Есть некоторые причуды, когда дело доходит до синтаксиса AT&T. Во-первых, обратите внимание на l суффикс в конце mov инструкция, это означает long и означает 32 бита данных. Другие суффиксы команд включают w за слово (16 бит - не путать с размером слова вашего процессора!), q для четырех слов (64 бита) и b для одного байта. Хотя это не всегда требуется, обычно вы увидите код сборки, в котором используется синтаксис AT&T, в котором явно указывается объем данных, с которыми работает команда.

Больше ясности требуется, когда дело доходит до режима адресации, используемого в операнде источника и назначения. $ Значит immediate адресация, так как используется значение в самой инструкции. В приведенном выше примере, если он был написан без этого $, direct будет использоваться адресация, т.е. ЦП будет пытаться получить значение по адресу памяти 1 (что, скорее всего, приведет к ошибке сегментации). % Значит register адресация, если вы не включили это в приведенный выше пример eax будет рассматриваться как symbol т.е. помеченный адрес памяти, который, скорее всего, приведет к undefined reference во время ссылки. Поэтому обязательно указывайте режим адресации, используемый как для операнда источника, так и для целевого операнда.

Способы операндов памяти также различаются:

Intel: [базовый регистр + индекс * размер индекса + смещение]

AT&T: смещение (базовый регистр, индекс, размер индекса)

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

должен, по крайней мере теоретически, производить тот же двоичный файл

Это полностью зависит от вашего набора инструментов.

Каковы причины, чтобы отдать предпочтение одному или другому?

Личные предпочтения, конечно, на мой взгляд, сводятся к тому, какой синтаксис вам удобнее при обращении к памяти. Предпочитаете ли вы принудительную ясность синтаксиса AT&T? Или вы предпочитаете, чтобы ваш ассемблер выяснил для вас эту мелочь?

Это параметры командной строки? Макросы? Не мнемонические ключевые слова?

Это связано с самим ассемблером (GAS, NASM). Опять же, личные предпочтения.

Почему бы не проверить этот пост?

Одно из самых больших различий между NASM и GAS - это синтаксис. GAS использует синтаксис AT&T, относительно архаичный синтаксис, специфичный для GAS и некоторых старых ассемблеров, тогда как NASM использует синтаксис Intel, поддерживаемый большинством ассемблеров, таких как TASM и MASM. (Современные версии GAS поддерживают директиву под названием.intel_syntax, которая позволяет использовать синтаксис Intel с GAS.)

Это покрывает:

  • Основные синтаксические различия между NASM и GAS
  • Общие конструкции уровня сборки, такие как переменные, циклы, метки и макросы
  • Немного о вызове внешних подпрограмм C и использовании функций
  • Различия в мнемонике сборки и ее использование
  • Методы адресации памяти

Хорошая практика - писать hello_world на обоих диалектах и ​​иметь конкретное ощущение.

Что хорошо в GAS, так это то, что он не пытается делать всевозможные причудливые карты. это заставляет вас указывать точное количество памяти и вычислительной мощности, которые вам нужны, что удерживает вас от совершения ошибок. NASM хорош, но если вам нужна эффективность, вам подойдут Tiny C и fasm.

Я думаю, что ключевым моментом является то, что NASM предназначен только для архитектуры Intel , а GAS — для многих архитектур, таких как, например, ARM и т. д.

Другие вопросы по тегам