ARM assembly-language programming for the Raspberry Pi
1. Introduction -- Not because they are easy...
“We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard...
-- John F Kennedy
Assembly language programming is hard, for many reasons. Even experienced programmers struggle with the need to focus on fine detail for a long period of time. Others don't want to deal with binary and hexadecimal, or to understand low-level concepts like flags and registers. The relative obscurity of the relevant software tools -- assemblers, disassemblers, linkers -- can be off-putting.
Nevertheless, learning to program in assembly language is rewarding -- not necessarily because it is useful, although sometimes it is -- but because of the deep knowledge that it forces us to gain. In assembly programming, all pretence is laid bare. You can't do it with an imperfect or superficial understanding.
The ARM-based Raspberry Pi is a good machine to use to learn assembly programming. You can learn the entire ARM instruction set in an hour, and the necessary software tools are widely available at little or no cost. If you have access to a Raspberry Pi, can use a text editor and type simple commands into a console, you can learn to program in assembly language.
The examples in this collection are intended to introduce assembly language programming from the very first principles. Each example builds on the previous one, adding a small amount of new information, building up to programs that can actually do useful things.
My examples don't rely on any other software, apart from the Linux kernel.
They don't link any libraries, even those that are likely to be found
on most Linux systems (like glibc
). Using libraries allows
more impressive results to be achieved quickly, but the whole purpose
of this exercise is to be educational. It's certainly worth studying
the internal operation of common libraries, but using them in
an educational context defeats the whole purpose. To be frank, it is
both possible, and instructive, to work without even an operating
system. The problem with this is that there is too much variation
even between different Pi boards to make the examples even remotely
portable.
My examples do assume some familiarity with procedural programming in general. You don't need to know much, but being able to run "Hello, World" in Python probably isn't enough by itself. I assume that the reader knows what a loop is, and a function call, and a variable. I don't assume familiarity with any particular programming language, but it's hard to avoid mentioning C -- because the Linux kernel is largely written in C.
These examples should work on any Raspberry Pi that runs any kind of Linux. They also work (I've tried) on Android (32-bit and 64-bit ARM versions), and will probably work on ARM-based Chromebooks. The problem with these platforms is that it can be awkward to obtain and install the necessary software tools -- not a problem at all on the Pi.
I should warn you that these examples do proceed in baby steps. It will take quite a few examples even to get to the "Hello, World" stage. I should also point out that my emphasis at all times is to use comprehensible code, not to strive for the most efficient implementation. I will be discussing efficiency as the series progresses, but I don't think it's something that newcomers to assembly programming should worry about at the start.
In these articles I show the complete source code of examples that are short enough for this to be practicable. For longer examples, I show only code that has changed since the previous example. Complete source code for all the examples is available on GitHub.
This series of examples is a work in progress. If you find the examples useful, please get in touch -- it will encourage me to produce more.