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 😉

8 thoughts on “Smallest application size for win32 console application

  1. Koro

    You forgot /OPT:NOWIN98 and /MERGE:.rdata=.text 🙂 It can be brought down to 1kb easily.

    Now if one does not care about Win9x compatibility, you can use /ALIGN:16 too.

  2. jkalmbach

    Yes, I did forget the /MERGE option! The NOWIN98 is not supported anymore (VS2008) and has no effect. The merging of both section will reduce the size to 1024 bytes.

    Also the usage of “/ALIGN:16” will reduce the size to 688 bytes!

    Thanks for your comment Koro!

  3. Pingback: __chkstk? | keyongtech

  4. Hamid

    Thanks Jochen. seems like mine doesn’t understand /ALIGN and /MERGE.
    what should i do?

    C:\Users\Administrator\Desktop>cl /c /O1 /GS- /ALIGN:16 /MERGE:.rdata=.text main
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80×86
    Copyright (C) Microsoft Corporation. All rights reserved.

    cl : Command line warning D9002 : ignoring unknown option ‘/ALIGN:16’
    cl : Command line warning D9002 : ignoring unknown option ‘/MERGE:.rdata=.text’

  5. jkalmbach Post author

    These are linker options!:

    cl /c /O1 /GS- smallest.cpp
    link /subsystem:console /MERGE:.rdata=.text /ALIGN:16 smallest.obj kernel32.lib

  6. required

    On a harddrive, all files are in multiples of sectors size or clustor sizes. For old hard drives, 2 TB or smaller, one sector is 512 Bytes. For new hard drives, more than 2 TB, one sector is 4096 Bytes. Thus, always round up to the nearest sector size unless you have sector overlap through compression.


Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha *