|
На счет языка я вижу два варианта:
ассемблер и C / C++. Хотя, возможно, что
4kIntro можно постараться написать на Delphi
или C#, но я бы не советовал.
Далее, компилятор. Если Ваш выбор C /
C++, то достойных компиляторов на сегодняшний
день два - это компиляторы от компаний
Microsoft и Intel. Какой именно компилятор
взять я вряд ли посоветую, нам ни разу не
приходилось писать маленькие интры на C /
C++. Вполне возможно, что компилятор от 5-й
студии для такой номинации как 4kIntro
окажется лучше, чем от 8-й или 7.1. Почему?
Потому что теперь для Вас главный приоритет -
это размер. Будьте готовы пожертвовать 50%
производительности ради двух-трех десятков
байт. Про память я вообще молчу, пользуйте на
здоровье. Если дополнительные 20 мегабайт
памяти сэкономят Вам 5 байт кода, обязательно
используйте эту возможность.
Если же Вы остановились на ассемблере,
то я однозначно рекомендую FASM. Я бы его
назвал самым демосценерским компилятором.
Именно на нем и были написаны наши 4kIntro
".factory." для Assembly'04 и ".morning
haze." для Chaos Constructions'04. В качестве
IDE рекомендую RadASM.
Если все же вы выбрали ассемблер, но
компилятор, который Вам приглянулся не FASM,
то я рекомендую пойти погулять, подышать
свежим воздухом, вернуться домой, снести все
компиляторы ассемблера и установить FASM.
Теперь что касается упаковщика. За время
существования демосцены были опробованы все
или почти все способы упаковки. Кто-то писал
свои пакеры, кто-то пользовался чужими, кто-
то комбинировал чужие пакеры с собственными
хитростями. Например, если заставить upx
паковать exe-шник как com-файл, то upx
запакует его заметно лучше. Поэтому писались
свои com-загрузчики, к которым дописывался
exe-шник и они окончательно паковались upx-
ом.
На сегодняшний день похоже, что
демосцена на Win32 в 4kIntro нашла для себя
окончательное решение. Этим решением оказался
архиватор cabinet, входящий в стандартную
поставку винды. За последние два года
демосцена в 4k практически полностью
перелезла на cabinet. Главное его достоинство
в том, что он входит в стандартную поставку
винды и интре не надо тащить за собой код
распаковки. Cabinet чаще всего обгоняет zip,
а иногда даже и rar. Это дает ему огромное
приемущество перед upx-ом, aspack-ом, и
прочими упаковщиками, которые хранят код
распаковки в самом exe-шнике.
По поводу звука существует три решения -
играть mid-ы с помощью DirectMusic, написать
собственный синтезатор (самый нелегкий, но
самый качественный путь) и, наконец, поискать
звуки в винде. Винда - это сотни мегабайт
халявной информации, в которой всегда можно
найти что-нибудь интересное. Главное, чтобы
файлы, которыми Вы воспользовались, входили в
стандартную поставку и присутствовали во всех
или почти всех виндах.
Теперь несколько советов по уменьшению
размера exe-шника.
Если Вы выбрали компилятор C / C++, то
обязательно разберитесь со всеми опциями
линкера, потому как именно он занимается
компоновкой exe-шника из объектников и, в
зависимости от параметров, переданных
линкеру, может нахаляву как убрать пару
килобайт, так и накинуть сверху. Так же
посмотрите опции компилера. Во-первых,
отключите RTL, а во-вторых, посмотрите все
оптимизации. Бывают ситуации, когда
оптимизация на скорость дает меньший exe-
шник, чем оптимизация на размер. Так что
теперь компилер и линкер это два божества,
которым Вы должны молиться перед сном.
Если же Ваш выбор - ассемблер, то никому
молиться не надо - что напишите, то и
получите. Достаточно просто знать ассемблер.
Итак, совет первый. Обрезать MZ-header
до 12-ти байт. Для этого существуют
специальные утилиты, их можно найти в сети.
Совет второй. Забейте нулями все поля PE-
header-а, которые не влияют на запускаемость
exe-шника. Так он лучше запакуется. Полей
этих немного и определить их можно
экспериментальным путем.
Совет третий. Запихните все в одну
секцию - код, данные и импорт. Название
секции оставьте пустым. Сишники - танцуйте с
бубном вокруг опции линкера "MERGE", а
название секции забейте нулями.
Совет четвертый. Импортируйте функции по
ординалу. Но будьте осторожны, во многих dll-
ках ординалы разные в разных виндах, так что
для начала выясните, какие функции можно
импортировать по ординалу, а какие придется
on имени.
И последнее. Группируйте данные по
типам. То есть целочисленные с
целочисленными, float-point-ы с float-point-
ами, текст с текстом. Есть хорошая
вероятность того, что пакер такой exe-шник
зажмет лучше.
И напоследок, несколько советов по
кодингу.
Сишникам я ничего советовать не буду -
молитесь божеству с именем cl.exe. Одному
Биллу Гейтсу известно какой код он собирает.
Советы ассемблерщикам:
Старайтесь выдерживать код наиболее
однородным. Так пакеру будет легче его
упаковать. Если Вам надо вызвать пять раз
подряд одну и ту же функцию с одними и теми
же параметрами, то сделайте это напрямую, не
пишите цикл. Если Вы в нескольких местах
считаете одну и ту же величину, считайте ее
одинаковым способом. К примеру, вот два
решения:
Вариант 1
invoke SomeProc, 0, 0, 1, 1
invoke SomeProc, 0, 0, 1, 1
invoke SomeProc, 0, 0, 1, 1
invoke SomeProc, 0, 0, 1, 1
Вариант 2
push 4
pop ecx
push 1
pop esi
push esi
pop edi
dec edi
.my_loop:
invoke SomeProc, edi, edi, esi, esi
loop .my_loop
Не смотря на то, что вариант 2 будет
более чем в 2 раза короче, вариант 1
упакуется лучше, потому что код более
однородный.
Далее, практически каждую операцию можно
решить множеством способов. Оцените каждый
способ по размеру и выберете наименьший. Не
забывайте придерживаться выбранного способа
везде. Например
mov eax, 23
на два байта длиннее, чем
push 23
pop eax
Какие-то два байта? Да, будьте готовы
экономить на каждом байте. Поверьте, ситуация
не из приятных, когда exe-шник весит 4'097
байт, а выкидывать уже нечего. Правило
автобуса тут не работает (в автобус всегда
влезет еще один человек).
В принципе по коду больше советов не
будет, не хотелось бы превращать статью в
уроки по программированию. До многих
тонкостей Вы дойдете сами.
Не забывайте периодически паковать
промежуточные результаты и смотреть, что у
Вас получается по размеру. Ассемблерщикам
советую останавливаться на 8-ми - 10-ти
килобайтах незажатого кода, сишникам - 12 -
20 килобайт, в зависимости от того, сколько у
Вас асмовых вставок. Скажу сразу: сишники, не
думайте, что в 12 килобайт на сях Вы впихнете
больше, чем ассемблерщики в 8 на асме. Все
дело в характере божества по имени "cl.exe".
На C / C++ код получается больше, но он более
однороден, поэтому упаковывается это дело
примерно в один размер.
Вообще говоря, проблему "4'097" можно
решить довольно хитрым образом. Пакер -
существо с характером. Достаточно переставить
местами две команды и вы можете выиграть
сразу 10 байт, а можете и проиграть все 30.
Так что, в крайнем случае, можно поиграться
перестановками. Только особо не увлекайтесь.
Подытожим наши действия.
- Определяемся с идеей
- Определяемся с инструментами.
- Аккуратненько и однородненько пишем
прогу.
- Дойдя до определенного размера,
говорим себе "стоп".
- Доводим синхронизацию интры с
музыкой.
- Собираем запакованый вариант и
смотрим, сколько байт у нас лишних.
- Оптимизируем интру на размер и
однородность.
Вот наверно и все. Напоследок добавлю,
что 7-й пункт самый страшный, особенно если
Вы не сумели вовремя остановиться, как это
было у нас с ".factory.". Тогда седьмой пункт
занял времени больше, чем шесть предыдущих.
Доходило до того, что я начинал непроизвольно
оптимизировать исходники на размер. Жаль, что
это не давало результатов :-) Но это уже
отдельная история. А я желаю Вам творческих
успехов, продуктивного демомейкинга, быстрых
процессоров, холодного пива и красивых
девочек. Увидимся
DEN/Bemz
Перейти к рубрике --> Демосцена |