As I believe the Raspberry Pi is quite a nice device for developing (basically a programming console, like game consoles) I thought it might be a nice idea to do some low-level programming on that thing. It is after all a rather slow deviceā¦
There is
some tutorial specifically for the Raspberry Pi
already, but this is very basic and the code that he writes is rather
complicated with complex instructions like stmfd
and ldmfd
. I went a
slightly easier route with
this tutorial.
The ARM architecture is kind-of a strange beast, because it can be low-level programmed in various ways. The first chips used 32 Bit instructions that are called “ARM” today. Some time later they added a 16 Bit instruction set called “Thumb”. Some years later, “Thumb2” came along, as a revised version of the original Thumb instruction set. The ARM1176 that is built into the Raspberry Pi supports ARM and Thumb instruction sets (some reviews state also Thumb2 which is not true – ARM1156 supports Thumb2 but that does not mean that ARM1176 does too). In the Raspberry Pi world, nobody seems to use Thumb1, therefore I’ll focus on the classical ARM instructions.
I’m assuming that you do have some experience with programming, so you more or less know how a C program looks like. In my experience it is usually quite easy to take a C program and go from there to the assembly program.
Without further ado, let’s start with one of the easiest programs ever:
So, if we take this and translate it roughly into ARM assembler:
To get an executable file, it is easiest to just run gcc
on it:
1 2 |
|
Run them and you’ll see they work just file and display Hello World
just
as expected. Let’s look at the binaries a bit closer to see what we actually
did:
1 2 3 4 5 6 7 |
|
The file
command tells us that we created an ARM executable file with 32
bit that uses shared libs. Which shared libraries? ldd
tells us that it
is libc, because of printf()
. In case you wonder what
libcofi_rpi is – an
optimized implementation of memcpy()
/memset()
for the Raspberry Pi
CPU. You don’t need to worry about this one.
The last command disassembles the binary again, so you can check what GCC did
exactly. If you check the disassembly of the main
label, you’ll see the
push
and pop
instructions in the disassembly, and in the
message
label you can find the “Hello World!\n” string which is rather
interesting if you’re new to ARM:
1 2 3 4 5 6 |
|
The first column is the address, the second column is the value at that address and the other colums are the decoded values. In the case of our string the address 83bc (as it is hexadecimal 0x83bc means the same thing) contains the value 6c6c6548 (again, in hex). If you know ASCII, you’ll notice that the ASCII representation of ‘H’ is the number 72 or in hex 0x48. If we continue, ‘e’ is 0x65 and ‘l’ is 0x6c. So the address 0x83bc contains the string “lloH”. Now, why is it reverse? Because the ARM architecture used in the Raspberry Pi is little-endian, which means that the representation is always reversed. By the way, this is also valid for x86 machines, they also use a little-endian representation. For more information, Wikipedia delivers.
And that concludes our short trip into ARM assembly. Stay tuned in case I’ll write some more about it.