I have the following C program:
#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. */ }
I compile it with GCC 4.8.2 using the following command line:
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 hc -lkernel32
The generated .exe file has a length of 2048 bytes. How to make it smaller using MinGW, preferably no more than 1024 bytes or (even better) no more than 512 bytes?
I would prefer a solution without writing assembler code, but I am also interested in assembler solutions.
I tried -Wl,-N to reduce the number of partitions (segments), but this caused segfault when running .exe in Wine.
This article assumes 480 bytes are possible. The following settings are used:
#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)
Unfortunately, these #pragma do not work with MinGW GCC. Are there any equivalents?
Here I was able to find the GCC -Wl,--section-alignment,16,--file-alignment,16 flags -Wl,--section-alignment,16,--file-alignment,16 which reduce the .exe size to 752 bytes. .Exe seems to work in Wine.
.rdata linker script, I was able to combine .data and .rdata and .rdata to 736 bytes. I use these GCC flags in addition to the ones above: -Wl,--section-alignment,16,--file-alignment,16,-T,tinygccpe.scr .
I am still looking for the MinGW equivalent /MERGE .
This question is similar, but it is not trying to drop below 9000 bytes.
I am also looking for the strip tool (the strip command in MinGW no longer reduces the size of .exe) that can remove the DOS stub (which is between the offsets 0x40 and 0x80, it contains. This program cannot be run in DOS mode. , We could save 64 byte). This code may remove it, but it also violates all absolute offsets in .exe. Unfortunately, the ld linker in MinGW cannot remove the DOS stub; it is hard-coded in the bfd/peXXigen.c , just above NT_SIGNATURE .
Is it possible to remove more headers from .exe, that is, headers that the loader does not use?