Learn x86-64 assembly by writing a GUI from scratch
Discussions: Hacker News, r/programming, Lobsters.
Most people think assembly is only to be used to write toy programs for learning purposes, or to write a highly optimized version of a specific function inside a codebase written in a high-level language.
Well, what if we wrote a whole program in assembly that opens a GUI window? It will be the hello world of the GUI world, but that still counts. Here is what we are working towards:
I wanted to expand my knowledge of assembly and by doing something fun and motivating. It all originated from the observation that so many program binaries today are very big, often over 30 MiB (!), and I asked myself: How small a binary can be for a (very simplistic) GUI? Well, it turns out, very little. Spoiler alert: around 1 KiB!
I am by no means an expert in assembly or in X11. I just hope to provide an entertaining, approachable article, something a beginner can understand. Something I wished I had found when I was learning those topics. If you spot an error, please open a Github issue!
Note: Authentication is optional in the X11 protocol, but some X11 servers e.g. XWayland require it. Authentication is skipped here and is handled in a separate article.
I will be using the nasm assembler which is simple, cross-platform, fast, and has quite a readable syntax.
For the GUI, I will be using X11 since I am based on Linux and it has some interesting properties that make it easy to do without external libraries. If you are running Wayland, it should work with XWayland out of the box (EDIT: After testing it, I can confirm it does work), and perhaps also on macOS with XQuartz, but I have not tested those (for macOS, remember to tell nasm to use the macho64 format, since macOS does not use the ELF format! Also, the stock linker on macOS does not support -static .).
Note that the only difference between *nix operating systems in the context of this program is the system call values. Since I am based on Linux I will be using the Linux system call values, but 'porting' this program to, say, FreeBSD, would only require to change those values, possibly using the nasm macros:
... continue reading