Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу).
Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Homepage Карта сайта Версия для печати

Джентльменский набор Web-разработчика   Ларри Уолл о Perl6   Наблы Система Orphus
 

28. Дзэн — Си — Win32

[27 января 2003 г.] обсудить статью в форуме

  Где я? кто я? куда я, куда?..
Наутилус Помпилиус

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

  1. получить эстетическое удовольствие;
  2. насладиться малым размером EXE-файла.

Вы можете и не получить всего этого. Да-да. Вы думаете, я вас вижу отсюда (сейчас, когда пишу эти строки)? Но я вижу лишь белый фон редактора и мигающий на нем курсор; звучит приятная музыка, а сзади тихо разговаривает телевизор. Солнечная система — 21-й век новой эры — январь — понедельник — восемь вечера — темнота за окном справа. Вас вообще может тут не быть.

Чайник 

Пожалуйста, обратите внимание на стиль оформления предыдущих двух пунктов. Смотрите на них до тех пор, пока вас не осенит. Мне это было бы приятно.

Но подождите-ка, мы забыли, что мир все-таки един в своем многообразии. А нельзя ли получить еще большее удовольствие, затратив столько же усилий и достигнув еще меньшего размера программы?

Сейчас модно поливать Microsoft грязью, однако сегодня нужную дверь показывает нам именно она. Итак, знакомьтесь: Microsoft Visual Studio 6.0. Visual C++, или просто Си. Имеем программу-заглушку:

Листинг 1
#include <windows.h>

// Параметры для минимизации размера EXE-файла.
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.reloc=.text")
#pragma comment(linker, "/FILEALIGN:512 /IGNORE:4078")
#pragma comment(linker, "/SECTION:.text,EWRX")
#pragma comment(linker, "/NODEFAULTLIB")
#pragma comment(linker, "/ENTRY:main")
#pragma comment(linker, "/SUBSYSTEM:console")
#pragma comment(linker, "/STACK:65536,65536")

// Основная функция.
int main(void) {
    // Можно и не вызывать ExitProcess.
    return 0;
}

Настройки компилятора (они установлены в DSP-файле, который доступен в архиве: http://dklab.ru/chicken/nablas/demo/minicpp; там же лежит и весь проект):

Листинг 2
/nologo /ML /W3 /O1 /D "WIN32" /D "NDEBUG" 
/D "_WINDOWS" /D "_MBCS" /Fp"Release/main.pch" 
/YX /Fo"Release/" /Fd"Release/" /Gs1048576 /FD //pre

Открываем, нажимаем F7 и — вуаля! — получаем EXE-файл размером ровно 1024 байта.

Чайник 

Заметьте, что по адресу http://dklab.ru/chicken/nablas/demo/minicpp/ps_universal располагается исходный код утилиты ps, предназначенной для определения идентификаторов работающих процессов. Она работает как в Windows 95 (и старше), так и в Windows NT, однако EXE-файл занимает уже 2 КБ (из-за небольшой несовместимости NT и не-NT пришлось фактически реализовывать 2 алгоритма в одном EXE-шнике).

Что вы можете делать на Си? Все то же самое, что и на ассемблере. Если уж на то пошло, то в Visual C++ есть возможность писать ассемблерные вставки прямо в середине Си-кода (см. директиву _asm в бессмертном MSDN-е). Конечно, функции вроде strlen, strcpy и т. д. недоступны (ибо они располагаются в «стандартных библиотеках», которые мы так старательно отключили). На счастье, для большинства из них есть замена в Windows API: lstrlen и lstrcpy соответственно.

Ну и напоследок несколько замечаний. Если вы скачаете архив проекта с http://dklab.ru/chicken/nablas/demo/minicpp, то cможете использовать как режим Release, так и Debug. Иными словами, вы не только получаете маленькие программы, вы можете еще и отлаживать их в режиме трассировки.

Если вы хотите создать новый проект самостоятельно, проделайте следующее.

  1. Выберите в New project тип Win32 Application. На следующем шаге обязательно укажите Create an empty project.
  2. Добавьте в проект файл, который начинается так же, как пример выше (указаны те же самые инструкции pragma). Этим вы как раз и добьетесь малого размера EXE-шника.
  3. Чересчур умный компилятор вставляет в функции, использующие для своей работы больше 4 K стека, обращение к специальной проверочной процедуре __chkstk. Беда в том, что последняя расположена в LIBC, которую мы отключили, а значит, линкер будет «ругаться». «Утихомирить» его у меня получилось только одним способом: задав параметр /Gs1048576 в параметрах компилятора. Это заставляет последний не трогать функции, использующие для локальных переменных меньше 1 МБ стека (думаю, таких большинство).
  4. И еще про стек. Нужно подкорректировать опцию линкера /STACK (при помощи #pragma), указав там через запятую два одинаковых числа — размер стека в байтах. Если стек переполнится, программа вылетит с ошибкой. Кстати, на размер EXE-шника этот параметр не влияет.

    Лирическое отступление 
    Обращаю ваше внимание, что значение параметра /Gs — это не размер стека, а лишь критерий, которым руководствуется компилятор при вставке кода вызова __chkstk.

  5. Release-версия уже будет компилироваться в EXE-файл размером 1 КБ. Однако с Debug-версией возникнут проблемы. Чтобы их решить, откройте Project Settings, перейдите на вкладку C/C++ и вручную сотрите в нижнем текстовом поле ключ /GZ. Кроме того, можете поставить Debug info равным Program database — это сократит размер EXE-шника в режиме отладки.
  6. Чтобы добиться наилучших результатов, включите оптимизацию в режиме Minimize size, поставьте тип процессора 80486 (для лучшей совместимости), а в Calling conversion укажите fastcall (последний совет, впрочем, спорный).

Лирическое отступление 
Львиную долю исследований по теме настоящей наблы провел Mikhail N. Kalinskiy в своей статье по адресу http://www.uinc.ru/articles/28/index.shtml. Скажем ему спасибо за это.

Если вам мало, вот еще одна статья, рекомендованная к изучению: http://freespace.virgin.net/james.brown7/tuts/minexe.htm (данная страница почему-то исчезла, так что приводится ссылка на ее копию). При написании данной наблы был использован материал и оттуда.

обсудить статью в форуме

 
Рекламный блок
   

Важное объявление:
    автор категорически против копирования и распространения в Интернете всех статей «Куроводства» с возрастом, меньшим 6 месяцев. Печальный опыт «расползания» чрезвычайно устаревших ошибочных версий статьи про Apache действительно объясняет такое решение.

Орфография на «Куроводстве»:
    если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Выделенный текст будет немедленно отослан вебмастеру, а Вы даже ничего и не заметите — настолько быстро все произойдет.

На заметку:
    если вы уже вскипели насчет дизайна этой страницы, то присмотритесь повнимательнее к названию, почитайте FAQ, сходите по лебедевским местам, как это уже предлагалось выше. Можно ли считать пародию плагиатом? Надеюсь, что нет.

Параметры этой страницы
   
GZip

Ссылки от спонсоров
    Рейтинг паркетной доски.


Дмитрий Котеров | 27 января 2003 г. ©1999-2016 | Генеральный спонсор: Хостинг «Джино» | Контакт Вернуться к оглавлению