У меня есть следующая программа C:Как создать крошечные PE (Win32) исполняемых файлов с помощью MinGW
#include <windows.h>
void __cdecl mainCRTStartup() {
DWORD bw;
HANDLE hfile = GetStdHandle(STD_OUTPUT_HANDLE);
WriteFile(hfile, "Hello, World!\r\n", 15, &bw, 0);
ExitProcess(0); /* Needed for successful (0) exit. */
}
я скомпилировать его с GCC 4.8.2, используя следующую командную строку:
i686-w64-mingw32-gcc -s -Os -fno-ident -fno-stack-protector -fomit-frame-pointer \
-fno-unwind-tables -fno-asynchronous-unwind-tables -falign-functions=1 \
-mpreferred-stack-boundary=2 -falign-jumps=1 -falign-loops=1 -mconsole \
-nostdlib -nodefaultlibs -nostartfiles -o h.exe h.c -lkernel32
Сгенерированный файл .exe имеет длину 2048 байт. Как уменьшить его с помощью MinGW, желательно не более 1024 байт или (еще лучше) не более 512 байт?
Я бы предпочел решение без написания ассемблерного кода, но меня также интересуют монтажные решения.
Я пробовал -Wl,-N
, чтобы уменьшить количество разделов (сегментов), но это вызвало segfault при запуске .exe в Wine.
Этот article предлагает использовать 480 байтов. Он использует следующие настройки:
#pragma comment(linker, "/FILEALIGN:16")
#pragma comment(linker, "/ALIGN:16")// Merge sections
#pragma comment(linker, "/MERGE:.rdata=.data")
#pragma comment(linker, "/MERGE:.text=.data")
#pragma comment(linker, "/MERGE:.reloc=.data")
#pragma optimize("gsy", on)
К сожалению, эти #pragma
s не работает с MinGW GCC. Есть ли эквиваленты?
В here Мне удалось найти флаги GCC -Wl,--section-alignment,16,--file-alignment,16
, которые снижают размер .exe до 752 байта. Кажется, что .exe работает в Wine.
От modifying the linker script Мне удалось объединить .data
и .rdata
и спуститься до 736 байт. Я использую эти флаги GCC в дополнение к перечисленным выше: -Wl,--section-alignment,16,--file-alignment,16,-T,tinygccpe.scr
.
Я по-прежнему ищу эквивалент MinGW /MERGE
.
This question похоже, но он не пытается опускаться ниже 9000 байт.
Я также ищу strip
инструмента (strip
команды в MinGW не уменьшает .exe размера любых дальнейший), который может удалить заглушку DOS (которая находится между зачетами 0x40 и 0x80, он содержит This program cannot be run in DOS mode.
, мы может сохранить 64 байта). This code может удалить его, но он также разбивает все абсолютные смещения в .exe. К сожалению, компоновщик ld
в MinGW не может удалить заглушку DOS, он жестко закодирован в файле bfd/peXXigen.c
, чуть выше NT_SIGNATURE
.
Можно ли вырезать больше заголовков из .exe, то есть заголовков, которые загрузчик не использует?
Связанная статья очень старая. Речь идет о VC++ 6, который был выпущен в 1998 году. Какова мотивация для попытки сделать ничего-ничего двоичного? Чтобы сделать что-нибудь продуктивным, вам захочется установить ссылку в библиотеке времени выполнения, что сделает ваш двоичный файл большим. Я, конечно, не сторонник написания * раздутого * кода (очень против этого тоже), но, на мой взгляд, вы наклонены на ветряные мельницы. Есть веские причины, по которым компоновщики вставляют прописку, и это просто не имеет значения, если у вас есть нетривиальное количество кода. (Несмотря ни на что, это - достойный вопрос.) –
@Cody Grey: Мотивация сохранения 1536 заголовков PE и байтов шаблонов в основном академическая. Эти байты, вероятно, не принесут заметной пользы для пользователя с современной многогигабайтной оперативной системой. Я также разрабатываю некоторые программы с небольшим общим количеством кода (менее 50 000 байтов при компиляции с указанными выше настройками). – pts
Помните, что на носителе существует минимальный размер кластера. например. в Windows это обычно 4k. Даже если вам удастся получить компоновщик для создания меньшего исполняемого файла, он все равно займет столько места на диске. – greatwolf