qrtris

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.

Implementation

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()

Build

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.c

If qrencode is installed, this Makefile directly outputs the QR code.

Result

You can find the project here: https://codeberg.org/matthinc/qrtris

The binary: qrtris.elf

The QR code