___                   ____            ___                  _
_/ /______ ________ / /_ ___ _ __/ _/______ __ _ ___\\/_ ___
_) _ /___\_ // _// /_____. \_ // /_____. (_ ____\ \
\ \ / / / \ _/ | / / _/ | / ___/___
/_________\ / /________\ \ |________\ \ |_____\ \ /
- -
diP---_ __ ___\------_ ____\_____|------_ ____\_____|----_ ___________\-
\___\  NEWS - RELEASES - TOOLS - ARTICLES - MEMBERS - LINKS

Generating small executables with Visual C++
by SpaceCommander / ByTeGeiZ


Last Changes: 11.11.2003


Introduction


This article explains how to set up an Visual C++ project that produces a very small executable.

Tools won't help, that available.
There's no linker that is able
to make an executable
with a size that's reasonable.

For a long time i had the opinion that it is impossible to generate small executables with Visual C++. Some years later i figured out how to setup a Visual C++ project that would be as small as the assembler version of this project.


Generating a new project


Go into Visual Studio menu and create a new empty Win32 Project. Create a new file named main.cpp and insert it into the project. Change the project configuration to Win32 Release. Paste following code in the main.cpp file:


    #include <windows.h>
    __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
    MessageBox(0,"test","test",MB_OK);
    return 0;
    }


If we now try to compile the project, we will get an executable file of 24 kb.


Final optimizations


After having a further look at the exe file, you can see "Microsoft Visual C++ Runtime Library" in it. Because I never said that i want this in my executable we have to remove it ;)
Replace the content of main.cpp file with:


    #pragma comment(linker,"/ENTRY:main")
    #include <windows.h>
    void main()
    {
    MessageBox(0,"test","test",MB_OK);
    }


The result will be an executable of 16 kb.
Now take a look at the exe file. The many zero bytes you will see are inserted due to enabled 4kb section alignment of windows exe files.
Insert at the beginning of main.cpp file


    #pragma comment(linker,"/OPT:NOWIN98")


Now we get an executable file of 2,5kb :) The resulting file will be runable on all windows versions.
Take a look at the exe file and you will see the sections .text (default code section), .rdata (default read-only data section) and .data (default read/write data section). We don't really need them, so we can merge these sections into one:


    #pragma comment(linker,"/MERGE:.rdata=.data")
    #pragma comment(linker,"/MERGE:.text=.data")
    #pragma comment(linker,"/IGNORE:4078")


YES! The resulting exe file has a size of 1 kb :] The ignore pragma is needed to disable the linker warning that occures due to the section merging, but can be ignored.
To improve build times and reduce the size of your application's precompiled header you can use:


    #define WIN32_LEAN_AND_MEAN



When using floating point numbers you will get an linker error. Use the following line to prevend this:


    #pragma comment(lib,"msvcrt.lib")



VC7 compatibility


VC7 does not allow to set all linker options with pragma's. We have to disable the not supported pragma's with #if statements and our options manually in project settings. Open the project settings and add /OPT:NOWIN98 to c++ command line options. Disable generation of debug info in linker settings and add /IGNORE:4078 to command line settings.


Final code of main.cpp


    #pragma comment(linker,"/ENTRY:main")
    #pragma comment(linker,"/MERGE:.rdata=.data")
    #pragma comment(linker,"/MERGE:.text=.data")
    #pragma comment(lib,"msvcrt.lib")
    #if (_MSC_VER < 1300)
    #pragma comment(linker,"/IGNORE:4078")
    #pragma comment(linker,"/OPT:NOWIN98")
    #endif

    #define WIN32_LEAN_AND_MEAN

    #include <windows.h>

    void main()
    {
    MessageBox(0,"test","test",MB_OK);
    }


Contact

SpaceCommander(at)ByTeGeiZ.de