
After watching this video https://www.youtube.com/watch?v=ExwqNreocpg, I wanted to build something similar for Linux. TL;DW: A guy was building a binary of a snake game that is so small it fits into a QR code. Instead of assembly, I decided to do it in C because that was the language I was interested in back then. Instead of snake, I built a very simple CLI version of Tetris.
My goal was to create a small statically-linked binary without any
dependencies. Therefore, even very basic libc functionality is not
available. I built the application by calling Linux system calls
directly, e.g. for exit:
#define exit(code) asm("int $0x80;" ::"a"(1), "b"(code))or write:
#define write(fd, str, len) asm volatile("int $0x80" ::"a"(4), "b"(fd), "c"(str), "d"(len) \
: "memory")print can then be implemented as write to
fd 1:
#define print(text, len) write(1, text, len)Since no libc is available, the program starts directly at the ELF entry point:
void _start()I experimented a lot with GCC arguments. I came up with the following Makefile that omits the stdlib and further reduces the binary size with some tweaks. Writing it was trial and error:
default: qr
qr: main
cat main | qrencode -8 -o qr.png
main: main.c
clang -s -Os \
-nostdlib \
-ffreestanding \
-fno-stack-protector \
-fno-unwind-tables \
-fno-asynchronous-unwind-tables \
-fomit-frame-pointer \
-ffunction-sections \
-fdata-sections \
-Wl,--gc-sections \
-static \
-z noseparate-code \
-o main main.cIf qrencode is installed, this Makefile directly outputs
the QR code.
You can find the project here: https://codeberg.org/matthinc/qrtris
The binary: qrtris.elf
