A short tutorial by Timo Wiren (glaze/biomassa^wAMMA)
Revision history | ||
Revision 1.0.5 | 2019-09-08 | Used LZMA instead of 7z, fixed some stuff to work on modern systems. |
Revision 1.0.4 | 2008-02-25 | Used 7z instead of gzip, -O1 instead of -Os and a few other things. |
Revision 1.0.3 | 2006-09-24 | Now using /tmp directory, little additions here and there. Marq: My last name is not Wigren ;-) |
Revision 1.0.2 | 2006-04-28 | Cleanup. |
Revision 1.0.1 | 2005-08-14 | Added a new URL and basic tips. Cleanup. |
1. About the author and this howto
2. Basic size optimization
3. Compressing the object code
4. Example code
5. Links to external websites
I'm a graphics programmer working in the games industry in Finland. I have been programming since 1998 and using GNU/Linux since 2001. I mostly develop graphics code, 2D and 3D, and use C and C++. I've been interested in demoscene since 1999, but I have released only few crappy half-done productions.
This howto does not cover all areas of size optimization. It mostly covers the usage of standard tools to produce smaller code. 32-bit OS, GCC, the C language and SDL 1.2 is used in this howto.
These are pretty basic things, but it doesn't hurt to mention them here:
-s
option to strip debug information.-s -R .comment -R .gnu.version
produce
nice results.-O1
or -Os
.static
saves space.-ffast-math -fomit-frame-pointer -fno-plt
.We can compress the binary and add decompression script in front of
it. To compress, use gzip --best -f program
or (better)
xz -c6 --format=lzma program >program.xz
Save the following decompression script to a file unpack.header:
a=/tmp/I;tail -n+2 $0|unxz>$a;chmod +x $a;$a;rm $a;exit
Now you can put the decompression script to the beginning of file and
your program after it:
cat unpack.header program.gz > program
Remember to make the resulting file executable: chmod +x program
.
Of course, there are more things you can do. LibC inserts standard and
bloaty code by default, so rename main()
to _start()
, and put the
following inline assembly code to the end of main function:
asm ( \
"movl $1,%eax\n" \
"xor %ebx,%ebx\n" \
"int $128\n" \
);
This ends the program without LibC code. Now you must compile it like this:
gcc -Os -fomit-frame-pointer -c program.c
ld -dynamic-linker /lib/ld-linux.so.2 program.o /usr/lib/i386-linux-gnu/libSDL.so -o program
Now you should be able to do 4k intros and the rest is up to smart algorithms and reuse of code and data. Of course there are many other small tricks that were not covered in this howto, but I'll add them when I remember those or find new ones.
XOR texture scroller (s.c):
/* XOR texture scroller begins */ #include <SDL/SDL.h> void _start() { int* v, x, y, w = 320, h = 240, i = 0; SDL_Surface* b; SDL_Event e; b = SDL_SetVideoMode(w, h, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL); v = b->pixels; do { SDL_PollEvent(&e); for (y = 0; y < h; ++y) for (x = 0; x < w; ++x) v[y * w + x] = (x+i) ^ y; SDL_Flip(b); ++i; } while (e.type != SDL_KEYDOWN); SDL_Quit(); asm ( \ "movl $1,%eax\n" \ "xor %ebx,%ebx\n" \ "int $128\n" \ ); } /* XOR texture scroller ends */
I was able to make the scroller binary size 694 bytes. I also have programmed a simple ray tracer under 2k.
gcc -O1 -ffast-math -fomit-frame-pointer -fno-plt -fno-stack-protector -c main.c
ld -dynamic-linker /lib/ld-linux.so.2 main.o /usr/lib/i386-linux-gnu/libSDL.so -o main
strip -s -R .comment -R .gnu.version main
./sstrip -z main
xz -c6 --format=lzma main >main.xz
cat unpack.header main.xz > main
chmod a+x main
rm main.xz
wc -c main
in4k, information about 4k coding on various platforms.
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux
Kickers of ELF, contains sstrip.
GC Masher, a tool that automagically tests gcc options for size optimization.