NASM Vs GAS (Практические отличия)
Я не пытаюсь спросить о том, что Intel против AT & T war (спорная точка, теперь, когда они поддерживают синтаксис Intel) или спрашивают, какой из них лучше "лучше", я просто хочу знать практические различия в выбирая один или другой.
В принципе, когда я собирал некоторые базовые сборки x86 несколько лет назад, я использовал NASM без каких-либо причин, кроме книги, которую я читал, тоже, что заставило меня твердо, но непроизвольно в лагере NASM. С тех пор у меня было очень мало причин использовать сборку, поэтому у меня не было возможности попробовать GAS.
Учитывая, что оба они поддерживают синтаксис Intel (что я лично предпочитаю) и должны теоретически, по крайней мере, создавать один и тот же двоичный файл (я знаю, что они, вероятно, не будут, но смысл не должен быть изменен), каковы причины в пользу того или другого?
Это параметры командной строки? Макросы? Немагнитные ключевые слова? Или что-то еще?
Спасибо:)
Ответы
Ответ 1
Синтаксис Intel: mov eax, 1 (назначение инструкции, источник)
Синтаксис AT & T: movl $1,% eax (источник инструкции, пункт назначения)
Синтаксис Intel довольно понятен. В приведенном выше примере количество перемещаемых данных выводится из размера регистра (32 бита в случае eax). Используемый режим адресации выводится из самих операндов.
Есть некоторые причуды, когда дело доходит до синтаксиса AT & T. Во-первых, обратите внимание на суффикс l
в конце инструкции mov
, это означает long
и означает 32 бита данных. Другие суффиксы инструкций включают
w
для слова (16 бит - не), которое должно быть путано с размером слова вашего
CPU!), q
для четырехзначного (64 бит) и b
для одного байта. Хотя это не всегда требуется, обычно вы увидите код сборки, который использует синтаксис AT & T, явно указывая количество данных, которыми управляет команда.
В режиме адресации, используемом в исходном и целевом операнде, требуется дополнительная разъяснительная информация. $
означает immediate
адресацию, так как используется значение самой инструкции. В приведенном выше примере, если он был написан без этой $
, будет использоваться адресация direct
, т.е. ЦП будет пытаться извлечь значение по адресу памяти 1 (что, скорее всего, приведет к ошибке сегментации). %
означает register
адресацию, если вы не указали это в приведенном выше примере eax
, будет рассматриваться как symbol
, то есть адрес помеченной памяти, что более чем вероятно приведет к undefined reference
в время ссылки. Поэтому обязательный явный для режима адресации, используемого и операндом источника и получателя.
Описанные операнды памяти также различаются:
Intel: [базовый регистр + индекс * размер индекса + смещение]
AT & T: смещение (базовый регистр, индекс, размер индекса)
Синтаксис Intel упрощает определение того, что происходит, чтобы найти адрес памяти. С синтаксисом AT & T результат будет таким же, но вы должны знать, что происходит вычисление.
должен, теоретически, по крайней мере, производить один и тот же двоичный
Это полностью зависит от вашей инструментальной цепочки.
Каковы причины того, чтобы поддержать тот или иной?
Индивидуальное предпочтение, конечно, по моему мнению, сводится к тому, какой синтаксис вам будет более комфортным при обращении к памяти. Вы предпочитаете принудительное объяснение синтаксиса AT & T? Или вы предпочитаете, чтобы ваш ассемблер выяснял эту минимальную мелочь для вас?
Это параметры командной строки? Макросы? Немагнитные ключевые слова?
Это связано с самим ассемблером (GAS, NASM). Опять же, личные предпочтения.
Ответ 2
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 созданием разделов и заполнением самих данных.