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

         

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


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

Сравнивая ассемблеры друг с другом, мыщъх не пытался найти "самый лучший" транслятор (таких просто не существует), а стремился свести воедино информацию о предоставляемых ими возможностях, ведь значимость любых критериев _всегда_ субъективна по определению. Человеку, упорно игнорирующего существование 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 – Ассемблер Высокого Уровня), другие — презирают их, ратуя за чистоту ассемблерного кода. Вот и разберись тут кто прав, а кто виноват! Макросы упрощают программирование, зачастую позволяя невозможное (например, шифровать код программы еще на стадии ассемблирования!), но переносимость программы от этого резко ухудшается и переход на другой транслятор становиться труднореализуемым. Но как бы там ни было, поддержка макросов совсем не обязывает этими макросами пользоваться!


Содержание раздела