СТАТЬИ > Assembler.Ru

Минимальное Windows-приложение на ассемблере

Вопрос о минимальной программе для того или иного языка программирования и операционной среды обычно возникает в следующих случаях:

  1. когда начинающий программист дочитывает до конца первую главу учебника и до него доходит, что большинство известных ему программ умеют нечто большее, чем тупо приветствовать мир. Пытливый ум новичка подсказывает ему, что если встречаются программы, умеющие больше этого, то, значит, где-то есть и программы, умеющие меньше
  2. когда начинающий программист робко, опасаясь быть проигнорированным, замодерированным или посланным, забрасывает вопрос в какую-нибудь конференцию. Последующие события, как правило, приводят его в шок, надолго отбивая охоту приступать к прочтению второй главы. Со всех концов бескрайней саванны мгновенно слетаются и сбегаются бесчисленные гуру, возникает потасовка, из облака пыли доносятся рык, ржание, визги и предсмертные хрипы, разлетаются перья и клоки шерсти. Великие считают и пересчитывают строчки в исходниках, потом буквочки в них же, а потом и байтики в екзешниках. Вопли стихают только после того, когда кто-нибудь предлагает подсчитывать биты, установленные в 1, и все вдруг понимают, почему двери в психушках открываются исключительно вовнутрь. Вывалив языки и тяжко дыша, братия расползается по своим кельям зализывать раны и готовиться к грядущим битвам. Посередине вытоптанной поляны, одинокий, жалкий и забытый, остывает трупик несчастного новичка
  3. когда новичок, отчаявшись познать истину самостоятельно или испить ее из ладоней великих, записывается на компьютерные курсы, и, с трудом досидев на первом занятии до сакраментального "У кого есть вопросы?", тянет руку и получает в ответ краткое изложение всей программы обучения. Затем, сверившись со списком группы и перезвонив в кассу, преподаватель также дает обещание, что к концу курса студент сам сможет элементарно ответить на этот простейший вопрос.

Между тем вопрос о минимальной программе - совсем не простейший, и представляет отнюдь не академический интерес. Минимальная программа, очевидно, решает две задачи: (1)стартует и (2)завершается в конкретной рабочей среде. И то, и другое она должна делать корректно, с тем, чтобы:

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

В C/C++, например, запуск и завершение приложения win32 поддерживаются скрытой от прикладного программиста функцией _WinMainCRTStartup, содержащейся в runtime-библиотеке. Именно ее вызывает операционная система при запуске приложения, а уж она, кое-чего поделав, вызывает ту самую WinMain, с которой начинается всякое приложение, базирующееся на win32. (Конечно, строго говоря, запуск приложения посредством вызова _WinMainCRTStartup - это свойство не языка, а операционной среды.) От программиста же требуется, чтобы WinMain была правильно оформлена (включая четыре входных параметра), и завершалась оператором return с кодом выхода типа int.
В языках программирования более высокого уровня для программиста все еще проще, хотя там уже вряд ли можно говорить о том, что приложение-де "непосредственно взаимодействует с операционной системой". Java, еще более высокий, чем C/С++, уже не использует фиксированное название стартовой функции, да и завершение программы в нем - это просто закрывающая фигурная скобка.

Однако, вернемся к ассемблеру. Вот обещанный текст минимального приложения для win32:

.386
.model flat,stdcall
ExitProcess PROTO :DWORD
.code
WinMain PROC PUBLIC hinst,prev_hinst,command_line,cmd_show
 ;...
 invoke ExitProcess,0
WinMain ENDP
end

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

Что здесь что и зачем?

Замечание 1. По поводу необходимости применения функции ExitProcess. Именно с ее помощью, а не посредством команды ret, как могли бы ожидать знатоки C/C++, должно завершаться приложение win32, написанное на ассемблере.

Если залезть внутрь runtime-библиотеки C/C++, то мы увидим, что именно так завершает работу приложения уже упоминавшаяся функция _WinMainCRTStartup. Но поскольку подключать runtime-библиотеку C/C++ к ассемблерной программе как-то нелогично (хотя и вполне возможно), мы должны вызвать ExitProcess "вручную". Только эта функция корректно завершает работу приложения, в частности, оповещая использовавшиеся приложением библиотеки DLL о необходимости декрементировать их счетчики занятости и, при обнулении последних, выгрузиться из памяти.

Замечание 2. А вот и обещанная плохая новость про параметры стартовой процедуры. Дело в том, что установкой их значений занимается - кто бы вы думали? - опять же _WinMainCRTStartup! И следовательно, в ассемблерных программах, где ее нет, при входе в WinMain параметры содержат:

Так что, воленс-ноленс, придется получать эту ценную информацию самостоятельно. Как говорится, клик хере.

Замечание 3. И все-таки приведенный текст приложения - не самый минимальный. Можно сделать его еще меньше, для чего следует убрать все параметры функции WinMain. Поскольку приложение собирается без runtime-библиотеки C/C++, это вполне допустимо, так как больше не с чем выполнять ее связывание. В результате объем исполняемого файла останется тем же, а вот объем исполняемого кода в нем (образа приложения) сократится аж до 7 байт. Про это стоит почитать еще.

Замечание 4. В этой статье рассматривается минимизация размера кода программы, но отнюдь не exe-файла, ее содержащего. Как известно, исполняемые файлы Windows обычно имеют так называемый PE-формат, и манипуляции с этим форматом дают некоторые возможности для сокращения размера файла. Например, можно вместо стандартной stub-программы использовать более компактную, собственной разработки.

  [C] Svet(R)off

© 2002-2004 wasm.ru - all rights reserved and reversed