Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GeorgyFirsov/dea2fbc31842cc91058b4139914b6ebf to your computer and use it in GitHub Desktop.
Save GeorgyFirsov/dea2fbc31842cc91058b4139914b6ebf to your computer and use it in GitHub Desktop.

Cравнение ассемблерных трансляторов

Крис Касперски, aka мыщъх, aka nezumi, aka elrton, aka souriz, no e-mail.

Проблема выбора "единственного правильного" ассемблерного транслятора мучает не только начинающих, но и профессиональных программистов. У каждого продукта есть своя когорта поклонниках и спор о преимуществах/недостатках рискует превратиться в священные войны с выносом тел погибших. На форумах такие дискуссии лучше не разводить и вещать в одностороннем порядке, как мыщъх, собственно, и поступил, сравнив MASM, TASM, FASM, NASM, YASM и некоторые другие ассемблеры по всему спектру критериев, значимость которых каждый должен оценивать сам.

Введение

Компиляторы языков высокого уровня (Си, Паскаль) в определенной степени совместимы между собой и хотя исходный текст, предназначенный для одного компилятора, не всегда без переделок транслируется на другом, синтаксис и прочие языковые концепции остаются неизменными, позволяя "летать" между MS VC, Intel C++, GCC, Open WATCOM, сравнивая полноту поддержки Стандарта, скорость трансляции, качество кодогенерации, популярность компилятора и вытекающее отсюда изобилие (недостаток) библиотек и компонент к нему.

С трансляторами ассемблера все обстоит иначе. Казалось бы, x86 ассемблер - он и в Африке ассемблер, так ведь нет! Помимо поддержки мнемоник машинных команд, каждый транслятор обладает своим собственным набором директив и макросредств, зачастую ни с чем не совместимых. Ассемблерный листинг, "заточенный", например, под MASM, бесполезно переносить на FASM, поскольку, возможности, предоставляемые макросредствами, у них сильно неодинаковые!

Перефразируя известную поговорку, можно сказать: выбирая транслятор ассемблера, вы выбираете судьбу, изменить которую впоследствии за здорово живешь не удастся! Придется переучиваться, фактически осваивая новый язык. Но это еще полбеды! Всякий уважающий себя программист со временем обрастает ворохом маленьких библиотек, делающих кучу грязной работы. Их-то куда при переходе на новый ассемблер девать?! Перенести ничуть не легче, чем переписать с нуля!

К счастью, ассемблер - это только инструмент, а не религия, и совместное использование нескольких трансляторов еще никто не запрещал. На практике, обычно, так и поступают. Ставится конкретная задача и для ее решения выбирается наиболее адекватный инструмент. Естественно, чтобы сделать правильный выбор необходимо знать какие ассемблеры вообще есть и чем они отличаются.

Основополагающие критерии

Богатый ассортимент - верный признак отсутствия продукта, который устраивает если не всех, то хотя бы большинство, а потому если что-то существует и не просто существует, но еще и собирает под свое крыло нехилое количество пользователей, значит, кому-то оно действительно необходимо и отстоем быть никак не может (это сразу, чтобы пресечь возможные разговоры шепотом).

Сравнивая ассемблеры друг с другом, мыщъх не пытался найти "самый лучший" транслятор (таких просто не существует), а стремился свести воедино информацию о предоставляемых ими возможностях, ведь значимость любых критериев всегда субъективна по определению. Человеку, упорно игнорирующего существование LINUX/BSD, абсолютно все равно на какое количество платформ был перенесен данный транслятор. А для кого-то это вопрос первостепенной важности!

Тем не менее, существует ряд основополагающий критериев, существенных для всех категорий программистов. Начнем с генерации отладочной информации, без которой отладка программы сложнее, чем "hello, word", превращается в настоящую пытку. Вот тут некоторые уже пытаются возразить, что ассемблерам, в отличии от языков высокого уровня, отладочная информация на хрен не нужна, ведь мнемоники машинных команд, что в листинге, что в отладчике - одни и те же. А метки?! А структуры?! А имена функций?! Уберите их - и код станет совершенно не читаемым! Можно, конечно, воспользоваться отладочной печатью (просто вставлять макрос, выводящий значение регистров/переменных на экран/файл в указанных местах) - давным-давно, когда интерактивных отладчиков и в помине не существовало, отладочная печать была основным средством борьбы с багами. Еще можно отлаживать программу, держа перед носом распечатку исходных текстов, но это извращение еще покруче будет.

Проблема в том, что формат отладочной информации не стандартизован и различные трансляторы используют различные форматы, что ограничивает нас в выборе отладчиков или вынуждает использовать конверторы сторонних производителей, а некоторые ассемблеры (например, FASM) не генерируют отладочной информации вообще. Ну хоть бы простейший map-файл, эх…

Но, если формат отладочной информации - это задний двор транслятора, то формат выходных файлов - это его лицо. Непосвященные только пожмут плечами. Какой там формат? Обыкновенный obj, из которого с помощью линкера можно изготовить все, что угодно - от exe до dll. На самом деле, "обыкновенных" объектных файлов в природе не бывает. Есть omf (в редакциях от Microsoft и IBM), coff, elf, aout и куча разной экзотики в стиле as86, rdf, ieee и т.д. Так же заслуживает внимания возможность "сквозной" генерации двоичных файлов не требующая помощи со стороны линкера. А некоторые ассемблеры (например, FASM) даже позволяют "вручную" генерировать исполняемые файлы и динамические библиотеки различных форматов полностью контролируя процесс их создания и заполняя ключевые поля по своему усмотрению. Впрочем, программы, целиком написанные на ассемблере, - это либо вирусы, либо демки, либо учебные, либо просто садомазохизм такой. Обычно на ассемблере пишутся лишь системно-зависимые компоненты или модули, критичные к быстродействию, которые затем линкуются к основному проекту и, если ассемблер генерирует только omf, а компилятор - coff, то… возникает проблема сборки "разнокалиберных" форматов воедино. Мыщъху известен только один линкер, умеющий это делать - ulink от Юрия Харона, он же обеспечивают не хилые возможности по сборке файлов "вручную", так что выбор конкретного ассемблерного транслятора целиком лежит на совести (и компетенции) программиста, но все-таки лучше, чтобы и ассемблер, и компилятор, генерировали одинаковые форматы объектных файлов.

Другой немаловажный критерий - количество поддерживаемых процессорных архитектур, которых в линейке x86 набралось уже больше десятка. Конечно, недостающие команды можно реализовать с помощью макросов или запрограммировать непосредственно в машинном коде через директиву DB, но… если так рассуждать, то зачем вообще нужны ассемблеры, когда есть hex-редакторы?! Особое внимание следует обратить на платформы AMD x86-64 и Intel IA64. Хотим ли мы этого или нет, но 64-разрядные архитектуры имеют хорошие шансы потеснить x86, поэтому учиться программировать под них обязательно, так что поддержка со стороны транслятора должна быть обеспечена уже сейчас!

Кстати, ни один из трансляторов не поддерживает набор команд x86-процессоров в полном объеме. Например, на MASM'е невозможно написать jmp 0007h:00000000h и приходится прибегать к различным ухищрениям: либо реализовать команду через DB, что не наглядно и неудобно, либо заталкивать в стек сегмент/смещение, а потом делать retf, но это длинно и к тому же воздействует на стек, которого у нас может и не быть.

Программирование на смеси 16- и 32-разрядного кода с кратковременным переходом в защищенный режим и возвращением обратно в реальный - это вообще песня и на MASM'е такое скорее умрешь, чем запрограммируешь, однако, большинству программистов подобного трюкачество просто не нужно!

А вот что реально нужно большинству - так это интеграция в мировое сообщество. Свои собственные оси обычно пишут пионеры, только что прочитавшие Юрова/Зубкова и открывшие для себя защищенный режим с его поистине безграничными возможности. В учебном плане, это, бесспорно, очень даже хорошо, но коммерческим программистам обычно приходится программировать под уже существующие системы, туже Windows, например. И, если в состав DDK входит MASM в кучей исходных текстов драйверов, то пытаться собрать их под другим транслятором - означает впустую убивать время. Опять-таки, если компилятору Microsoft Visual C++ задать ключ /FA, то он выдаст ассемблерный листинг в стиле MASM, точно так же поступит и IDA Pro, Borland C++ выберет TASM (ну еще бы!), а GCC - GNU Assembler (он же GAS). Вот это и называется интеграцией в среду. Чистый ассемблер сам по себе мало кому интересен и практически всегда он становится приложением к чему-то еще. То есть, если вы пишите драйвера под Windows на Microsoft Visual C++, то разумнее всего остановить свой выбор на MASM'е, поклонникам же Borland C++ лучше TASM'а ничего не найти. Под Linux/BSD рулит GAS (GNU Assembler) уже хотя бы за счет того, что ассемблерные программы можно транслировать с помощью компилятора GCC, используя Си-сопроцессор с одной стороны и освобождаясь от головной боли с поиском стартового кода и библиотек, однако, GAS использует AT&T-синтаксис, являющийся полной противоположностью Intel-синтаксису, которого придерживаются MASM, TASM, FASM, NASM/YASM, поэтому в данной статье не рассматривается. Разработчики вирусов и просто маленьких ассемблерных программ, написанных из любви к искусству, намного меньше ограничены в своем выборе и могут использовать все, что им по душе, вне зависимости от степени "поддержки".

Качество документирования играет весьма важную роль и еще важнее кому принадлежит проект. Трансляторы, созданные энтузиастами-одиночками, могут умереть в любой момент, поэтому закладываться на них в долговременной перспективе мыщъх ни за что бы ни стал. Коммерческие ассемблеры крупных компаний выглядят намного более стабильными и непоколебимыми, однако, никаких гарантий, что в один "прекрасный" момент компания не забьет на своей продукт у нас нет (достаточно вспомнить историю с TASM'ом). Открытые трансляторы, поддерживаемые независимой группой лиц, наиболее живучи. Стоило коллективу NASM'а чуть-чуть приостановить его развитие, как тут же появился YASM - "позаимствовавший" исходные тексты и добавивший все необходимое (поддержку x86-64, формат отладочной информации CodeView и т. д.).

Последнее, на чем хотелось бы заострить внимание - это макросредства. Отношение к ним у программистов двоякое. Одни во всю пользуются плодами прогресса, программируя на смеси ассемблера, бейсика и препроцессора си (существует даже проект HLA: High Level Assembler - Ассемблер Высокого Уровня), другие - презирают их, ратуя за чистоту ассемблерного кода. Вот и разберись тут кто прав, а кто виноват! Макросы упрощают программирование, зачастую позволяя невозможное (например, шифровать код программы еще на стадии ассемблирования!), но переносимость программы от этого резко ухудшается и переход на другой транслятор становится труднореализуемым. Но как бы там ни было, поддержка макросов совсем не обязывает этими макросами пользоваться!

MASM

Продукт жизнедеятельности ранней компании Microsoft, которой тот был нужен для создания MS-DOS (исходные тексты MS-DOS 6.x, добытые из парнокопытного животного все поимели? Видели, сколько там ассемблерных вставок?), а позднее и для Windows 9x/NT. После выхода версии 6.13 продукт на некоторое время тормознул в развитии, но потом здравый смысл взял вверх и последняя версия (на момент написания этих строк - 6.13.8204) поддерживает уникод, все SSE/SSEII/SEEIII расширения (объявляемые двумя директивами .686/.XMM), а так же архитектуру AMD x86-64. Платформа Intel IA64 не поддерживается, но Microsoft поставляет Intel-ассемблер IAS.EXE.

Аббревиатура MASM расшифровывается отнюдь не как Microsoft Assembler, а как Macro Assembler, то есть Ассемблер с поддержкой Макросов, покрывающих своими возможностями широкий круг задач: повторения однотипных операций с параметризацией (шаблоны), циклические макросы, условное ассемблирование и т.д., по сравнению с которым препроцессор языка Си выглядит жалкой подделкой. Имеется даже зачаточная поддержка основных парадигм ООП, впрочем, так и не получившая большого распространения, поскольку ассемблер и ООП концептуально несовместимы. Многие пишут даже без макросов на чистом ассемблере, считая свой путь идеологически наиболее правильным. Но о вкусах не спорят.

Сначала MASM распространялся в виде самостоятельного (и притом весьма дорогостоящего) пакета, но позже он был включен в состав DDK, которое вплоть до Windows 2000 DDK раздавалось бесплатно, а сейчас доступно только подписчикам MSDN. Впрочем, вполне полноценное DDK (с ассемблером) для Windows Server 2003 входит в Kernel-Mode Driver Framework, а сам транслятор MASM'а еще и в Visual Studio Express, которая такая бесплатна.

Стив Хатчессон собрал последние версии транслятора MASM'а, линкер от Microsoft, включаемые файлы, библиотеки, обширную документацию, статьи разных авторов, посвященные ассемблеры и даже простенькую IDE в один дистрибутив, известный под "пакетом хатча" (hutch), бесплатно раздаваемый всем желающим на вполне лицензионной основе, так что это не хак, а вполне удобный комплект инструментов для программирования под Windows на ассемблере.

MASM'у посвящено множество книг, что упрощает процесс обучения, а в сети можно найти кучу исходных текстов ассемблерных программ и библиотек, освобождающих программиста от необходимости изобретать велосипед. Также, MASM является выходным языков для многих дизассемблеров (Sourcer, IDA Pro). Все это делает MASM транслятором номером один в программировании под Wintel.

Поддерживаются два выходных формата: 16/32 Microsoft OMF и (16)/32/64 COFF, что позволяет транслировать 16/32-разрядные программы под MS-DOS, работающие в реальном и защищенном режиме, 16-разрядные приложения и драйвера для Windows 3.x, 32-разряныые приложения и драйвера для Windows 9x/NT, а так же 64-разрядные приложения и драйвера для Windows NT 64-bit Edition. Для создания бинарных файлов потребуется линкер, который умеет это делать (например, ulink от Юрия Харона). Кстати говоря, последние версии штатного Microsoft Linker'а, входящее в SDK и DDK, утратили способность собирать 16-разряные файлы под MS-DOS/Windows 3.x и приходится возвращаться к старой версии, которая лежит в папке NTDDK\win_me\bin16.

MASM генерирует отладочную информацию в формате CodeView, которую Microsoft Linker может преобразовывать в PDB-формат, хоть и не документированный, но поддерживаемый библиотекой dbghelp.dll, позволяющей сторонним разработчикам "переваривать" отладочную информацию, поэтому, файлы, оттранслированные MASM'ом, можно отлаживать в Soft-Ice, дизассемблировать в IDA Pro и прочих продуктах подобного типа.

Главный недостаток MASM'а - его жуткая багистность. Стоит только открыть Knowledge Base, посмотреть на список официально подтвержденных багов и… ужаснуться! Как только после этого на MASM'е вообще можно программировать?! Особенно много ошибок в штатной библиотеке. Вот только несколько примеров: dwtoa и atodw_ex не понимают знака и по скорости очень тормозят, хотя в документации написано:

A high speed ascii decimal string to DWORD conversion for applications that require high speed streaming of conversion data

ucFind не находит в строке подстроку, если длина подстроки равна 1 символу; функции BMHBinsearch и SBMBinSearch (поиск алгоритмом Бойера-Мура) реализованы с ошибками; некоторые функции обрушивают программу (если передать ustr2dw строку длиннее пяти байт - программа падает).

Другой минус - отсутствие поддержки некоторых инструкций и режимов адресации процессора, например, невозможно сделать jmp far seg:offset, а попытка создания смешанного 16/32 разрядного кода - это настоящий кошмар, который приходится разгребать руками и всячески извращаться, преодолевая сопротивление "менталитета" транслятора.

Наконец, MASM - типичный коммерческий продукт с закрытыми исходными текстами, судьба которых покрыта мраком. Microsoft интенсивно продвигает высокоуровневое программирование, отказываясь от ассемблера везде, где это только возможно, поэтому, не исключено, что через несколько лет MASM прекратит свое существование...

Тем не менее, несмотря на все эти недостатки, MASM остается самым популярным профессиональным транслятором ассемблера при программировании под Windows NT, хотя разработчикам приходится плеваться и материться, но реальных альтернатив ему нет.

TASM

Самый популярный транслятор ассемблера времен MS-DOS, созданный фирмой Borland (известной в народе как Багдад), и полностью совместимый с MASM'ом вплоть до версий 6.x и поддерживающий свой собственный режим IDEAL с большим количеством улучшений и расширений.

Удобство программирования, скромные системные требования и высокая скорость трансляции обеспечивали TASM'у лидерство на протяжении всего существования MS-DOS (буква "T" означает Turbo, вот так - без ложной скромности). Но с появлением Windows популярность TASM'а стала таять буквально на глазах. Не сумев (или не захотев) добиться совместимости с заголовочными файлами и библиотеками, входящими в комплект SDK/DDK, фирма Borland решила поставлять свой собственный порт, причем далеко неидеальный. К тому же штатный линкер tlink/tlink32 не поддерживает возможности создания драйверов, а формат выходных файлов (Microsoft OMF, IBM OMF, Phar Lap), не поддерживается текущими версиями линкерома от Microsoft (впрочем, 16-битные версии это умеют). В довершении ко всему, формат отладочной информации не совместим с CodeView и реально поддерживается только TurboDebugger'ом и soft-ice.

И хотя эти проблемы в принципе разрешимы: возможность низкоуровневого ассемблерного программирования (без включаемых файлов и макросов) осталась там же, где и была, несовместимость форматов компенсируется наличием конверторов, но… преимущества режима IDEAL над стандартным синтаксисам MASM'а день ото дня казались все менее и менее значительными, ряды поклонников редели и в конце концов проект загнулся. Последней версией транслятора стал TASM 5.0, поддерживающая команды вплоть до 80486 процессора. Отдельно был выпушен патч, обновляющий TASM до версии 5.3 и поднимающий его вплоть до Pentium MMX, однако, команды Pentium II такие, например, как SYSENTER как не работали, так и не работают. Поддержка уникода тоже отсутствует.

В настоящее время Borland прекратила распространение своего ассемблера и достать его можно только в магазинах торгующих старыми CD-ROM или у какого-нибудь коллекционера. Пацак по кличке !tE выпустил пакет TASM 5+, включающий в себя транслятор, линкер, библиотекарь, какое-то подобие документации, несколько заголовочных файлов под Windows и пару демонстрационных примеров. Когда будете искать это добро не перепутайте его с TASM32 фирмы Squak Valley Software - это совершенно независимый кроссассемблер, ориентированный на процессоры 6502, 6800/6801/68HC11, 6805, TMS32010, TMS320C25, TMS7000, 8048, 8051, 8080/8085, Z80, 8096/80C196KC, о которых большинство из нас в лучшем случае просто слышало, что они есть.

Короче, TASM - это труп. Причем вполне конкретный. Однако, для разработки прикладных приложений под Windows 16/32 и MS-DOS он все-таки подходит, особенно, если вы уже имеете опыт работы с ним и некоторые собственные наработки (библиотеки, макросы), с которыми жалко расставаться, а конвертировать под MASM - весьма проблематично. Возможно, вам понравится бесплатный Lazy Assembler (автор - Половников Степан), совместимый с режимом IDEAL TASM и поддерживающим команды из наборов MMX, SSE, SSEII, SSEIII, 3DNow!Pro.

FASM

Писать о культовых проектах, не затронув чувства верующих и сохранив при этом здоровую долю скептицизма и объективизма не так-то просто, особенно если ты сам являешься апологетом веры, за которую готов если не отдать жизнь, то уж точно порвать любого критика на куски, а потом прихлопнуть дампом памяти или своп файлом. FASM (расшифровывается как Flat Assembler - Ассемблер Плоского Режима) - это крайне необычный транслятор с экзотичными возможностями, которых все мы давно (и безуспешно!) ждали от крупных производителей, но те были слишком далеки от практического программирования и пытались формировать новые потребности (например, путем введения поддержки ООП), вместо того, чтобы удовлетворять те, что есть.

Так продолжалось до тех пор, пока Томаш Гриштар (Tomasz Grysztar) - аспирант Ягеллонского университета в Кракове - не задумал написать свою собственную ось, названную Титаном и представляющую некоторое подобие DOS-системы для защищенного режима. Перебрав несколько ассемблерных трансляторов, но так и не обнаружив среди них подходящего, Томаш пошел на довольно амбициозный шаг, решив разработать необходимый инструментарий самостоятельно. Это произошло в 1999-03-23, 14:24:33 (дата создания первого файла) и уже к началу мая 1999 года появилась версия, способная транслировать сама себя (FASM написан на FASM'е). Операционная система в результате одной случайной катастрофы пала смертью храбрых, а вот исходные тексты FASM'а - остались и с тех пор он продолжает активно развиваться.

Что же такое FASM? Это ассемблер с предельно упрощенным синтаксисом (никаких offset'ов и прочих захламляющих листинг директив), полной поддержкой всех процессорных команд (в том числе и jmp 0007:00000000), качественным кодогенератором, мощным макропроцессором и гибкой системой управления за форматом выходных файлов.

FASM распространяется в исходных текстах на бесплатной основе и к настоящему моменту перенесен на MS-DOS, Windows 9x/NT, LINUX, BSD, поддерживает уникод и все x86 процессоры вплоть до Pentium-4 с наборами мультимедийных инструкций MMX, SSE, SSEII, SSEIII, AMD 3DNow!, а так же платформу AMD x86-64, позволяя генерировать не только Microsoft coff, но и готовые bin, mz, pe и elf файлы. То есть, фактически, FASM позволяет обходиться без линкера, однако, при этом раскладку секций в PE-файле и таблицу импорта приходится создавать "вручную" с помощью специальных директив ассемблера, что выглядит очень заманчиво, но на практике все же намного удобнее сгенерировать coff и скомпоновать его с модулями, написанными на языках высокого уровня.

Макроязык FASM'а настолько мощный, что позволяет писать программы на себе самом без единой ассемблерной строки, вот например (см. листинг 1). И пускай кто-то ворчит, ну вот, мол, еще одна попытка опустить ассемблер до уровня Бейсика. Ничего подобного! Макросы - вещь добровольная. Хочешь - пользуйся, не хочешь - не надо.

file 'interp.asm'
repeat $
    load A byte from %-1
    if A>='a' & A<='z'
        A = A-'a'+'A'
    end if
    store byte A at %-1
end repeat

Листинг 1. Программа, целиком написанная на интерпретируемом языке FASM'a

Все это были достоинства. Теперь поговорим о недостатках. Ни на что не похожий синтаксис FASM'а напрягает даже матерых программистов, заставляя их вгрызаться в плохо структурированную документацию и небольшое количество демонстрационных примеров, поставляемых вместе с транслятором. На это требуется время, которое в конечном счете ничем не компенсируется, поскольку, круг задач, на которых FASM реально рвет MASM крайне мал. Категорическая несовместимость с MASM'ом чрезвычайно затрудняет разработку Windows-драйверов (в большинстве своем создаваемых на основе примеров из DDK). Прикладным задачам в свою очередь требуется SDK и желательно первой свежести, а не второй, да и программы, целиком написанные на ассемблере, - это совсем не то, чего требует бизнес-машина. "Математические" задачи, перемножающие матрицы, вычисляющие координаты пересечения кривых в N-мерном пространстве или трансформирующие графику - легко пишутся на FASM'е, поскольку не привязаны к конкретной операционной системе, никаких API-функций они не вызывают и вообще не лезут туда, где можно обойтись Си/Си++.

Если бы FASM поддерживал генерацию отладочной информации, его (с некоторой натяжкой) еще было бы можно рассматривать как серьезный инструмент, а так… он остается игрушкой, пригодной для мелких задач типа "hello, world", вирусов, демок и прочих произведений хакерского творчества.

Наконец, ни у кого нет гарантий, что создатель FASM'а не утратит к нему интереса, а ведь без поддержки новых процессорных инструкций всякий транслятор обречен на медленное, но неизбежное вымирание. Открытость исходных текстов тут не поможет, помимо них нужна еще и команда. Нужны "носители знания", способные удержать детали проекта у себя в голове, а тот факт, что FASM написан на себе самом, увы, читаемости листингам отнюдь не добавляет.

NASM

Транслятор NASM (расшифровывается как Netwide Assembler - Ассемблер Шириной Во Всю Сеть или просто Расширенный Ассемблер) вырос из идеи, поданной на comp.lang.asm.x86 (или возможно на alt.lang.asm - сейчас точно никто и не помнит), когда не было ни одного хорошего свободного ассемблера под x86. FASM'а тогда еще не существовало. MASM/TASM стоили денег и работали только под MS-DOS/Windows. Единственный более-менее работающий транслятор под UNIX - GAS (GNU Assembler) завязан на компилятор GCC и имеет такой ужасный синтаксис, что писать на нем могут только мазохисты (и ведь примеров программ, запрограммированных на GAS'е практически нет!). Остальные ассемблеры (типа A86, AS86) не позволяют писать 16/32 разрядный код или раздаются практически без документации.

Кончилось это дело тем, что группа программистов во главе с Петром Анвином (Peter Anvin) решила разработать собственный ассемблер и это у нее получилось! MASM-подобный синтаксис, достаточно мощная макросистема (впрочем, несовместимая с MASM'ом и ничего не знающая об union'ах вместе с кучей других полезных фич), поддержка всей линейки x86 процессоров вплоть до IA64 в x86-режиме, богатство выходных файлов (bin, aout, aoutb, coff, elf, as86, obj, win32, rdf, ieee), генерация отладочной информации в форматах Borland, STABS и DWARF2 вкупе с портами под MS-DOS, Windows, Linux и BSD обеспечили NASM'у неслабую популярность, однако, без ярко выраженного фанатизма, характерного для FASM'а. Количество ошибок в трансляторе довольно невелико, причем в отличии от работающих продуктов (MASM/TASM) при "хитрых ошибках" NASM не падает, а генерирует ошибочный (по структуре) объектный файл. Вот и ищи как он его сгенерировал чем хочешь (даже матерым хакерам это сложно, а нормальный программист может даже и не пытаться). И, как это принято в Open Source community, полное игнорирование баг-репортов "неудобных" для авторов (разработки даже утверждают, что ошибок в их трансляторе вообще нет, в смысле им не известен ни один). Тем не менее, в последней версии NASM'а, в зависимости от значения ключа -On, код может сгенерироваться в 2х или более экземплярах, или может пропасть весь экспорт (pubdef'ы).

К минусам NASM'а можно отнести отсутствие поддержки уникода, платформы AMD x86-64, формата отладочной информации CodeView и некоторые странности синтаксиса. В частности, команда mov eax, 1 не оптимизируется и транслятор умышленно оставляет место для 32-разрядного операнда. Если же мы хотим получить "короткий" вариант, размер операнда необходимо специфицировать явно: mov eax, byte 1, что очень сильно напрягает или… использовать опцию "-On" для автоматической оптимизации.

Также необходимо принудительно указывать длину переходов short или near, иначе очень легко нарваться на ругательство "short jump out of range". Впрочем, опять-таки, существует возможность настроить транслятор на генерацию near-переходов по умолчанию.

Гораздо хуже, что NASM не помнит типы объявляемых переменных и не имеет нормальной поддержки структур (впрочем, самое понятие "нормальности" структур в ассемблере весьма растяжимо и каждый волен трактовать его по своему).

Из мелких недочетов можно называть невозможность автоматического генерации короткого варианта инструкции push imm8 и отсутствие контроля за соответствием транслируемых инструкций типу указанного процессора (команда cpuid под ".486" ассемблируется вполне нормально, а ведь не должна).

Непосредственная трансляция примеров из SDK/DDK под NASM'ом невозможна, так что разрабатывать на нем драйвера под Windows может только очень крутой поклонник или извращен. NASM - один из лучших ассемблеров под Liux/BSD, а вот под Windows его позиции уже не так сильны (в основном из-за неполной совместимости с MASM'ом).

YASM

Когда развитие NASM'а затормозилось, его исходные тексты легли в основу нового транслятора - YASM, что в зависимости от настроения может расшифровываться и как: Yes, it's an assembler, и как Your favorite assembler, и как Yet another assembler, и даже как Why an assembler (последнее - шутка).

Вот основные отличительные черты YASM'а от его предшественника: поддержка платформы AMD x86-64, большое количество исправленных ошибок (которых в NASM'е "нет"), оптимизированный парсер, переваривающий синтаксис как NASM, так и GAS, более полная поддержка COFF (DJGPP) и Win32 obj выходных файлов, генерация отладочной информации в формате CodeView, интернационализация (выполненная через GNU-библиотеку gettext), и прочие мелкие улучшения, которых вполне достаточно, чтобы потеснить NASM особенно в мире UNIX-подобных систем, где GAS-синтаксис по-прежнему играет ведущую роль.

Под Windows же YASM не имеет никаких ощутимых преимуществ перед MASM'ом за исключением того, что поддерживает возможность генерации двоичных файлов, особенно удобных для создания shell-кода, но бесполезных для разработчика драйверов.

Заключение

Попробуем подвести итог, обобщив все вышесказанное в нескольких словах (по одному слову для каждого транслятора):

  • MASM (Macro Assembler) - стандарт де-факто при программировании под Windows 9x/NT;
  • TASM (Turbo Assembler) - медленно разлагающийся труп, пригодный только для MS-DOS;
  • Lazy Assembler - реинкцинация TASMа с поддержкой новых команд процессора;
  • FASM (Flat Assembler) - неординарный и весьма самобытный, но увы, игрушечный ассемблер;
  • NASM (Netwide Assembler) - хороший ассемблер под LINUX/BSD с Intel-синтаксисом;
  • YASM (Yet another assembler) - усовершенствованный вариант NASM'а;
  • HLA (High Level Assembly Language) - очень высокоуровневый ассемблер, на любителя.

⚠ В текст оригинала статьи внесены правки: исправлены некоторые стилистические и орфографические ошибки. Кроме того, добавлены конструкции разметки Markdown'а.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment