skip to Main Content

Creating small executables with Microsoft Visual Studio

Starting with an empty project, I will show you how to use Microsoft Visual Studio 2010 to compile your C code without the usual bloating that the compiler adds automatically. This article will just feature C code, I may extend this blog entry for usage with C++ at a later point.

In the empty workspace, create a new file called tinyexe.c with following content:

#include <windows.h>

void main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Switch the solution configuration from Debug to Release and compile the project (F7 is the default key for this). The output will be a 6.656 byte sized exe file. Could have been worse I would say 🙂 Let’s have a look at what is inside the exe, I am using the file view of Total Commander which will give you a nice view of the file content and showing zero bytes as whitespace.

This is the portable executable header, containing 5 section definitions (.text, .rdata, .data, .rsrc, .reloc).

The code section contains way more code than needed for calling the 2 Windows APIs in our code.

This section contains the import table, import address table as well as a reference to a .pdb debug info file. In the list of imported API functions you will see way more APIs than the 2 that we actually intended to use. The reference to mscvrt.dll means that this exe uses functions of the Microsoft Visual C Run-Time Library, which we did not intend to do. The Visual Studio compiler adds the crt library initialization code by default which then calls our main function.

At the end of this exe file you can see a manifest xml file followed by relocation data, both features we do not need.

Lets see how we can pimp that exe (without using external tools) now:

  • To get rid of the console window that pops up on program start set the project option Linker/System/Subsystem to Windows (/SUBSYSTEM:WINDOWS)
  • Set the project option Linker/Advanced/Entry Point to main. This will remove the crt library initialization code and since we don’t use any C standard library functions also the reference to the msvcrt dll.
  • Set Linker/Debugging/Generate Debug Info to No. This will remove the .pdb debug information file reference.
  • Set Linker/Manifest File/Generate Manifest to No. Now the manifest xml is removed.
  • Set Linker/Advanced/Randomized Base Address to No. We don’t need relocations for a normal non library project.

Compile the project again and the resulting exe file will now be 2.048 byte small and look like this:

Between the DOS stub and PE header you can find the undocumented Rich Signature from Microsoft, which is present in newer Visual Studio compiler versions and is not needed, so you could zero those bytes out.

Creating small executables with Qt Creator and MingW

Starting with an empty Plain C Project in Qt Creator IDE and gcc from MinGW as compiler, I will show you how to generate small binaries that are independent from MinGW dlls. At the writing of this article the app versions that I used were Qt Creator 2.6.2 with Qt 5.0.1 and gcc 4.7.2.

Replace the code of the main.c with following:

#include <windows.h>

void main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Switch the build configuration in menu Projects from Debug to Release and compile the project (Ctrl + B is the default shortcut for this). This will result in a 9.728 byte big exe file. The file content, split in parts, looks like this:

This is the portable executable header, containing 8 section definitions (.text, .data, .rdata, .eh_fram, .bss, .idata, .CRT, .tls).

The code section is nearly as twice as huge as the one generated by Visual Studio compiler and of cause way more than we want inside our exe for calling 2 API functions.

In the import section you can see that it not only includes the Microsoft Visual C Run-Time Library, but also the MingW runtime.

Let’s pimp the project to remove all the stuff that we did not want included in the exe file:

  • Open the .pro file of your project and replace it with following:
CONFIG -= qt
DEFINES -= QT_LARGEFILE_SUPPORT UNICODE
SOURCES += main.c
QMAKE_CFLAGS += -fno-asynchronous-unwind-tables
QMAKE_LFLAGS += -static-libgcc -nostdlib
LIBS = -lkernel32 -lmsvcrt -luser32
  • If you try to build the project now you will get an linker error about undefined reference to `__main’. To fix this issue we just rename the main function in our c file:
#include <windows.h>

void __main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Recompile the project and your compiled exe will have a size of 2.048 byte and look so fresh and so clean like this:

Back To Top