How to create 4KB Linux binaries that render a 3D scene?

c, executable, linker, linux

Solution

The main reason why with the standard settings you can't make a small tool is that a lot of symbols and references to standard libraries are pulled into your binary. You must be explicit to to remove even that basic stuff.

Here's how I did it:

http://phresnel.org/gpl/4k/ntropy2k7/

Relevant Options:

Mostly self-explaining:

gcc main.c -o fourk0001 -Os -mfpmath=387 \
  -mfancy-math-387 -fmerge-all-constants -fsingle-precision-constant \
  -fno-math-errno -Wall -ldl -ffast-math -nostartfiles -nostdlib  \
  -fno-unroll-loops -fshort-double

Massage:

`strip` helps you get rid of unneeded symbols embedded in your binary:

strip -R .note -R .comment -R .eh_frame -R .eh_frame_hdr -s fourk0001

Code:

You may have to tweak and trial and error a lot. Sometimes, a loop gives smaller code, sometimes a call, sometimes a force inlined function. In my code, e.g., instead of having a clean linked list that contains all flame transforms in fancy polymorphic style, I have a fixed array where each element is a big entity containing all parameters, used or unused, as a union of all flames as per Scott Draves flame paper.

Your tricks won't be portable, other versions of g++ might give suboptimal results.

Note that with above parameters, you do not write a `main()` function, but rather a `_start()` function.

Also note that using libraries is a bit different. Instead of linking SDL and standard library functions the classy, convenient way, you must do it manually. E.g.

void *libSDL = dlopen( "libSDL.so", RTLD_LAZY );
void *libC = dlopen( "libc.so", RTLD_LAZY );
#if 1
    SDL_SetVideoMode_t sym_SDL_SetVideoMode = dlsym(libSDL, "SDL_SetVideoMode");
    g_sdlbuff = sym_SDL_SetVideoMode(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
#else
    ((SDL_SetVideoMode_t)dlsym(libSDL, "SDL_SetVideoMode"))(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
#endif


//> need malloc, probably kinda craft (we only use it once :| )
//> load some sdl cruft (cruft!)
malloc_t sym_malloc = dlsym( libC, "malloc" );
sym_rand   = dlsym( libC, "rand" );
sym_srand  = dlsym( libC, "srand" );
sym_SDL_Flip          = dlsym(libSDL, "SDL_Flip");
sym_SDL_LockSurface   = dlsym(libSDL, "SDL_LockSurface");
sym_SDL_UnlockSurface = dlsym(libSDL, "SDL_UnlockSurface");
sym_SDL_MapRGB        = dlsym(libSDL, "SDL_MapRGB");

And even though no assembler has to be harmed, your code might yield UB.

edit:

Oops, I lied about assembly.

void _start() {
    ...
    asm( "int $0x80" :: "a"(1), "b"(42) );
}

this will make your program return 42.

Problem

I just learned about the 4k demo scene contest. It consists in creating a 4KB executable which renders a nice 3D scene. The cited demo was build for Windows, so I was wondering, how one could create 4KB OpenGL scenes on Linux. A bare "hello world" already consumes 8KB: ``` $ cat ex.c #include <stdio.h> int main() { printf("Hello world\n"); } $ gcc -Os ex.c -o ex $ ls -l ex -rwxrwxr-x 1 cklein cklein 8374 2012-05-11 13:56 ex ```

Original source