How to create 4KB Linux binaries that render a 3D scene?
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.
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux is an interesting article that goes through a step-by-step process to create an ELF executable as small as possible.
I don't want to spoil the ending, but the author gets it down to a lot smaller than 4K ;)
Take a look at this article in KSplice blog from a while back. It talks about linking without the standard libraries.
https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_free