Daily Archives: 2008/02/02

Smallest application size for win32 console application

Several times someone asked the question: “Why is a simple console application 52 KB (CRT statically linked) or 7 KB (CRT as DLL) in size?”

The answer is: Because it uses the CRT 😉

Just to show you, that you can have smaller applications, here is (from my point of view) the smallest “usefull” application (Hello world):

// Filename: smallest.cpp 
#pragma comment(linker, "/entry:entry") 

void entry() 
  TCHAR szText[] = TEXT("Hello world\n"); 
  DWORD dwWritten; 
  WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szText, lstrlen(szText), &dwWritten, NULL); 

You must compile and link this file with:
cl /c /O1 /GS- smallest.cpp
link /subsystem:console smallest.obj kernel32.lib

Then you get an EXE file with 2048 Bytes.

You can even reduce it more if you merge the sections together and specify an alignment for the linker (but then program will then not run on Win98;) ):
cl /c /O1 /GS- smallest.cpp
link /subsystem:console /MERGE:.rdata=.text /ALIGN:16 smallest.obj kernel32.lib

Then you get an EXE file with 688 Bytes (VS2008) / 768 Bytes (VS2010).

So the question is: why does the CRT need so much space?

Most of the space is needed for “security reasons”. That is also the reason why I needed the specify the “/GS-” compiler switch to reduce the exe size. If you enable the buffer security checks, it triggers the compiler to use several functions and structures, which must be provided by the CRT.
And if you use the CRT, it also provides the default entry point and initializes all kind of stuff like calling constructors of static/global classes and others.
These are the main reasons why the CRT uses so much memory.

Another think is: if you want to use floating-point values, you also need the CRT. The reason is not very obvious for me… but the compiler is triggering the symbol “_fltused” to be linked with the image. If you provide your own “implementation” of this variable, it seems to work; but I don’t understand why the compiler is needing this variable. This variable must be set to a “magic” value (0x9875); I don’t know where this value comse from (expect it is defined in the CRT sources).

If you want to compile these samples from within the VS (2008) IDE, then you need to change the following setings from the default “Win32 Console Application”:

  • Switch to “Release” configuration
  • C/C++|Code Generation|Buffer Security Check: No (/GS-)
  • Linker|Debugging|Generate Debug Info: No 
  • Linker|Advanced|Entry Point: entry
  • Linker|Advanced|Randomize Base Address: Disable Image Randomization (/DYNAMICBASE:NO)
  • Linker|Advanced|Fixed Base Address: Image must be loaded at a fixed address (/FIXED)
  • Manifest Tool|Input and Output|Embed Manifest: No

And then you have your 2KB application from within the IDE 😉