Inspired by a Youtube video, I wanted to try out by myself, how small I could get the binary of the following C source code:
#include <stdio.h> void main() { for ( int i = -9; i < 10; i++, fputc( '\n', stdout ) ) for ( int j = 0; j < 19; j++ ) fputc( ((i*i-j*j)%6)?' ':'*', stdout );
The code itself has a size of just 175 bytes:
-rw-r--r-- 1 martin 175 2. Feb 18:32 muster.c
Now let's see the different sizes of the executables:
100 % – GCC
gcc -s -Os -o muster muster.c ls -o -rwxr-xr-x 1 martin 14424 2. Feb 19:20 muster -rw-r--r-- 1 martin 1168 2. Feb 19:11 muster.o
Compared to the size of the source code I find this binary size to be huge. Therefor I now tried different compile, link and strip options to make this binary smaller and smaller. I'll give it away first: On Linux I managed to make a binary of one fifth of the original size, already stripped. But let's see.
75% – GCC optimized
gcc -s -Os -Wl,-z,norelro -Wl,--build-id=none -fno-stack-protector -fno-unwind-tables -o muster muster.c strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag muster ls -o -rwxr-xr-x 1 martin 10792 2. Feb 18:49 muster -rw-r--r-- 1 martin 1600 2. Feb 18:31 muster.o
29% – TCC
tcc -s -Os -o muster muster.c ls -o -rwxr-xr-x 1 martin 4088 2. Feb 19:10 muster -rw-r--r-- 1 martin 1168 2. Feb 19:11 muster.o
21% – TCC with musl clib
tcc -s -Os -o muster muster.c ls -o -rwxr-xr-x 1 martin martin 2972 2. Feb 19:25 muster -rw-r--r-- 1 martin martin 1168 2. Feb 19:11 muster.o
With the right compiler both the object code as well as the resulting binary can be generated much smaller. Remark: All binaries are already stripped.
I plan to do the same tests with different C compilers for CP/M for 8080 and Z80 microprocessors to see what is possible on such very memory constrained systems with just a total of 64 KB.
For source code see first pinned comment in the following video:
🌐 Video: Oscar64, C compiler for Commodore 64