Как сократить количество нулевых байтов в exe-файле?

Тема в разделе "WASM.BEGINNERS", создана пользователем Andrystepa, 12 дек 2005.

  1. Andrystepa

    Andrystepa New Member

    Публикаций:
    0
    Регистрация:
    27 июн 2005
    Сообщения:
    13
    Адрес:
    Москва
    Написал простейшую консольную прогу под Windows на MASM32. Прога спрашивает имя и выдает приветствие. После компиляции релиза получилось 2506 байт ехе-файл. Однако открыв его в НЕХ-редакторе с удивлением обнаружил, что эти байты в подавляющем большинстве нулевые. В Инете нашел такой ответ, что компилятор выравнивает секции экзешника на 512 байтные границы, заполняя все нулями.

    Переписал прогу, оставив только секцию кода, получилось 1536 байт, но все равно подавляющее их большинство - нули. Откуда они и как от них избавиться?
     
  2. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    укажи линкеру ключ /FILEALIGN:0x200

    не используй много инициализированных данных



    пропатчи линкер, на предмет лишней информации записываемой

    в заголовок файла
     
  3. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Andrystepa

    Правильно, согласно спецификации PE-формата секции в файле должны быть выравнены на степень 2 от минимум 512 байт (размер сектора) до 64K. Поэтому сделать выравнивание менее чем на 512 вроде как нельзя. Соответсвенно оставшееся место от конца данных до ближайшей границы 512 забивается нулями. Экзешник должен содержать как минимум PE-заголовок и секцию кода, выравненную на 512. Размер файла также выравнивается компилятором на 512 байт, поэтому мин.размер составляет 1024 байта. Если добавить еще одну секцию (импорт или данные), то будет минимум 1536 байт и т.д. Масм по умолчанию создает таблицу импорта в отдельной секции .rdata, вот и получается минимум 3*512=1536 (PE,код,импорт). В фасме, кстати можно размещать таблицу импорта в секции кода, поэтому мин.размер получаетя 2*512.

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



    Asterix

    > "пропатчи линкер..."

    Ну ты насоветуешь ;) Как ни крути, но из-за выравнивания секций размер заголовка не может быть меньше 512 байт

    А FILEALIGN:0х200 это и есть 512 по умолчанию ;)
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    leo



    От себя добавлю, что в NTFS маленькие файлы полностью располагаются в записи MFT (размер которой 1Kb), поэтому имеет смысл делать такие файлы, иначе получаем сразу 1 кластер (4К) занимаемого места. А вот больших файлов с нулями бояться особо не стоит, ибо реально эти нули не сохраняются на диск.
     
  5. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    leo





    в масме тоже можно, не надо вводить в заблуждение :)







    я машинально ответил %)







    по умолчанию не для всех линкеров иначе не писали бы

    /opt:nowin98 или /FILEALIGN:0x200
     
  6. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576




    здесь да, но в общем случае это работает



    файл собранный пропатченным линкером получается 2Кб

    не пропатченным 2,5Кб
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Asterix

    > "в масме тоже можно, не надо вводить в заблуждение"

    А я и не говорил, что нельзя ;) Просто я этого не знаю, поэтому выбрал осторожную формулировочку типа "по умолчанию" ;)



    IceStudent

    > "ибо реально эти нули не сохраняются на диск"

    Это почему же ? Автокомпрессии какая рулит или что ?
     
  8. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    leo

    Да, Sparse files — сохраняется лишь размер блока, заполненного нулями. Драйвер потом просто обнуляет буфер для данных файла, переданный ему.



    Ну, а компрессия — это уже когда сами данные жмутся LZ-подобной компрессией. И выставляется атрибут "Compressed".
     
  9. Andrystepa

    Andrystepa New Member

    Публикаций:
    0
    Регистрация:
    27 июн 2005
    Сообщения:
    13
    Адрес:
    Москва
    Asterix

    leo

    „В фасме, кстати можно размещать таблицу импорта в секции кода, поэтому мин.размер получаетя 2*512.“



    в масме тоже можно, не надо вводить в заблуждение :)



    А как это делается в MASMе?
     
  10. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    смотри опцию линкера /MERGE
     
  11. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    в строку для линкера добавить



    /MERGE:.idata=.text /MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,EWR /IGNORE:4078
     
  12. Andrystepa

    Andrystepa New Member

    Публикаций:
    0
    Регистрация:
    27 июн 2005
    Сообщения:
    13
    Адрес:
    Москва
    Строка линкера в проекте у меня получилась такая: 5,O,$B\LINK.EXE /SUBSYSTEM:CONSOLE /RELEASE /VERSION:4.0 /MERGE:.idata=.text /MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,EWR /IGNORE:4078 /LIBPATH:"$L" /OUT:"$5",3

    Однако в результате линкер выдает такую ошибку:

    LINK : fatal error LNK1104: cannot open file "EWR /IGNORE:4078 /LIBPATH:C:\Masm32\Lib /OUT:$5.obj"

    т.е. он почему-то принимает опции EWR за имя файла. Почему??
     
  13. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Andrystepa

    используй bat файл

    всякие makefile'ы - зло
     
  14. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    радасм кстати тоже, фтопку радасмы
     
  15. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Asterix

    всякие makefile'ы - зло

    Дремучий ты.
     
  16. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    q_q

    тогда ответь человеку о просветленный :)
     
  17. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Andrystepa



    RTFM: в параметрах командной строки в радасме ',' — это спецсимвол, вместо него использовать '|':

    /section:.text|ewr



    Asterix



    Примитив :) Особенно, в 9х.



    makefile не зло, а нужный инструмент. Хотя иногда это как из пушки по воробьям.





    Каждому своё. Кто-то и в фаре на C# кодит..
     
  18. Andrystepa

    Andrystepa New Member

    Публикаций:
    0
    Регистрация:
    27 июн 2005
    Сообщения:
    13
    Адрес:
    Москва
    С "|" все получилось, но вот только размер исполнимого файла все равно 1536 байт. Что с объединенными секциями, что нет.
     
  19. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Asterix

    тогда ответь человеку

    Не вижу смысла в. Предполагаю, что следующий вопрос Andrystepa будет: "Почему файл на диске занимает 1Кб, а в диспетчере задач память процесса - 1Мб?"
     
  20. netex

    netex New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2005
    Сообщения:
    114
    Адрес:
    Russia
    Перед заголовком PE идет DOS'овский заголовок MZ с небольшой прграммкой ("заглушкой)". Это с ее помошью можно увидеть фразочку:

    "This program cannot be run in DOS mode", когда прога для Windows запускается в DOS.

    Советую всегда заменять эту "заглушку" на свою собственную, меньшую по объему.

    Это можно сделать так:

    1. Берем HEX редактор

    2. Пишем в нем:



    4D 5A 00 00 01 00 00 00 02 00 00 00 FF FF 00 00 00 00 00 00

    00 00 00 00 40 00 00 00 00 00 00 00 B4 4C CD 21 00 00 00 00

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    00 00 00 00





    B4 4C CD 21 это:



    MOV AH,4CH

    INT 21H



    Краткое описание основных полей MZ заголовка:



    +0000h 2 байта "MZ"



    +0004h 2 байта Длина файла MZ-формата в 512-байтных страницах



    +0008h 2 байта Длина заголовка в параграфах



    +000Ah 2 байта Минимальное количество дополнительных параграфов,

    необходимых для исполнения программы

    +000Ch 2 байта Максимальное количество дополнительных параграфов,

    необходимых для исполнения программы



    +0014h 2 байта Значение, загружаемое в регистр ip во время загрузки

    программы в память

    +0016h 2 байта Значение, загружаемое в регистр cs во время загрузки

    программы в память (формируется загрузчиком)

    +003Сh 4 байта В нем содержится смещение, указывающее на начало PE-файла

    формируется при линковке нашей заглушки и PE файла



    3. Сохраняем этот код в файл с именем my_stub.exe

    4. При линковке PE файла добавляем опцию /STUB:<путь к файлу my_stub.exe>



    И еще можно просто изменять выравнивание при линковке PE файла:

    1. Добавить опцию при линковке PE файла /ALIGN:4