Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #71, ОКТЯБРЬ 2006 г.

война миров

КРИС КАСПЕРСКИ АКА МЫЩЪХ

Спецвыпуск: Хакер, номер #071, стр. 071-024-1


АССЕМБЛЕР ПРОТИВ СИ

ДЕЙСТВИТЕЛЬНО ЛИ ЭФФЕКТИВНЫ (НЕЭФФЕКТИВНЫ) СИ-КОМПИЛЯТОРЫ, И НАСКОЛЬКО БОЛЬШЕ МОЖНО ВЫИГРАТЬ, ПЕРЕПИСАВ ПРОГРАММУ НА ЯЗЫКЕ АССЕМБЛЕРА? КАКУЮ ЦЕНУ ЗА ЭТО ПРИДЕТСЯ ЗАПЛАТИТЬ? ПОСТАРАЕМСЯ ДАТЬ ПРЕДЕЛЬНО ОБЪЕКТИВНЫЙ И НЕПРЕДВЗЯТЫЙ ОТВЕТ

Любовь хакеров к ассемблеру вполне понятна и объяснима. Разве не заманчиво знать язык, которым владеют немногие? Ассемблер окружен мистическим ареолом — это символ причастности к хакерским кругам, своеобразный пропуск в клан системных программистов, вирусописателей и взломщиков. Ассемблер теснее всех других языков приближен к железу, и ниже его находятся только машинные коды, уже вышедшие из употребления, а жаль!

Программисты каменного века с презрением относились к ассемблеру, поскольку для тех времен он был слишком высокоуровневым языком, абстрагирующимся от целого ряда архитектурных особенностей. Программируя на ассемблере, можно не знать последовательность байт в слове, систему кодирования машинных инструкций; ассемблер скрывает тот факт, что команда «ADD AL, 6h» может быть закодирована и как «04h 06h», и как «80h C0h 06h». Хуже того: ассемблер не предоставляет никаких средств выбора между этими вариантами. Хорошие трансляторы автоматически выбирают наиболее короткий вариант, но никаких гарантий, что они это сделают, нет, а в самомодифицирующемся коде это весьма актуально! Да что там самомодифицирующийся код (или код, использующий коды мнемоник как константы) — на ассемблере невозможна эффективная реализация выравнивания команд! Тупая директива align, вставляющая NOP'ы, не в счет. В частности, «ADD AL, 6h», закодированная как «80h C0h 06h», намного эффективнее, чем «04h 06h + 90h (NOP)».

Кто-то, наверняка, скажет: «Ассемблер позволяет закодировать любую команду через директиву DB, следовательно, на нем можно делать все». Весьма спорное утверждение. Си так же позволяет объявлять массивы вида unsigned char buf[] = «\x04\x06\x90» и умеет преобразовывать указатели на данные в указатели на функции. Рассуждая по аналогии, можно сказать, что на Си легко сделать то же самое, что и на ассемблере, даже не используя ассемблерных вставок (которые, на самом деле, не часть языка, а самостоятельное расширение). Но вряд ли программу, полностью состоящую из «\x04\x06\x90», можно назвать программой на языке Си. Точно так же и с ассемблером. Это вовсе не язык неограниченных возможностей, каким его иногда представляют. Ассемблер — всего лишь средство выражения программисткой мысли, рабочий инструмент. А выбор инструмента всегда должен быть адекватен. Не стоит рыть траншею лопатой, если под рукой есть экскаватор, но и строить собачью конуру из бетонных блоков с помощью крана — не верх инженерной культуры, а признак ее отсутствия :).

Считается, что программа, написанная на ассемблере, по определению компактнее и производительнее аналогичной программы, написанной на языке высокого уровня. Действительно, человек всегда в состоянии обогнать даже самый совершенный компилятор, потому что компилятор действует по строго заданному шаблону (точнее, нескольким шаблонам), а человек способен на принципиально новые решения. Однако, ассемблерные программы, написанные начинающими программистами, как правило, значительно хуже кода, сгенерированного компилятором. Распределение переменных по регистрам, устранение зависимостей по данным, переупорядочивание инструкций с целью предотвращения простоев конвейера — это слишком нудная работа, отнимающая кучу сил и времени. И хотя человек потенциально способен добиться намного лучшего распределения, чем компилятор, этот разрыв не настолько велик и с коммерческой точки зрения ничем не окупается.

Содержание  Вперед на стр. 071-024-2