This is my first of hopefully many articles on
I want to talk about a RISC architecture that has become one of my biggest hobbies lately, the ARM architecture.
ARM Ltd makes RISC Processors for embedded systems, and has become increasingly popular in todays consumer electronics. It's so widespread that you probably own one yourself. The GP2X console and Nintendo's GBA comes to mind, as well as a lot of cellular phones. With this in mind, let's start some hacking!

How to get started:
You can buy one of these:
1.) a GBA handheld and flash cartridge. link
2.) a GP2X handheld + Board with JTAG. link
3.) an ARM evaluation board. link
4.) Get a emulator like SkyEye or QEMU

I must admit I'm a bit biased towards the GP2X. It's not too expensive, and it's not quite as boring as emulators and evaluation boards due to its 320x240 color LCD screen and stereo sound. Besides, it hasn't just one ARM CPU, it has two! Both CPUs are clockable in software and boost 266 mhz and 32 KB cache. The system has 64 MB ram and a lot of peripherals. All this runs on two puny AA-sized NiHM batteries. So if you ask me, it's a real bargain.

In order to build anything, you need development tools, which consist of a C/C++ compiler, an assembler, a linker, an object dumper and a symbol stripper as a bare minimum. All these tools together are called a toolchain. (C coders you know what I'm talking about) There are a few options available:

1.) Devkitpro works for mostly everything ARM-based, but if you want to go the GP2X route, I recommend
2.) the Open2X Toolchain. They are both based off the famous GCC, the toolchain available on Linux, BSD and Solaris distros.
3.) Build your own from scratch by fetching sources/patches here

As soon as you have your toolchain up and running, it's time to actually compile something!
I hope I'm not insulting anyone's intelligence by writing this mandatory Hello World example in C :-)

Coding an example and running it.

#include < stdio.h >
int main(void)
printf("Hello World!\n");
return 0;

Compile it with:
whatever-prefix-gcc -o helloworld -static sourcefile.c

Why the -static? Well, unless you are 110% sure that your toolchain's libc version is exactly the same running on your embedded ARM system, you have to statically compile libc into your executable. The downside is that some DNS lookup functions (a part of POSIX) won't work. gethostbyname to name one. But then again, nothing is perfect.
If you somehow get a set of C libraries compiled for the host but don't want to mess with the libc version already on the system, you can override the libc path for one particular session with /lib/ (see here for more information regarding this)
The application writes to STDOUT, so unless you run a debugger-session or have a shell/terminal you won't see much.
Congrats! You have your first shell application running on an ARM system! Now let's see if we can cut down on the size. That pesky C library sure takes a lot of space, right?
Well, luckily we don't have to link against a single library at all, if all we need is basic functionality like mmap and puts. The kernel gives us this functionality through what we call syscalls. On the x86 platform you call the mnemonic INT. On ARM we have the mnemonic SWI.
For 2.4 kernels all parameters to syscalls are in the same order as the registers, starting from r0 and up. The actual syscall is decided by the value followed by SWI. As seen in the header unistd.h, each syscall value is offseted by 0x900000. You can find all the syscall numbers listed in the 2.4 ARM kernel sources in the path ./arch/arm/kernel/calls.S
There is also an online list here, but it's not for ARM specifically, and it's pretty outdated. Take it with a pinch of salt. The function prototypes for each syscall are found in the C header unistd.h as well.

Okay, without any C code or external linking, let's make a new hello world example:

@adr and adrl are ARM GAS psuedo-instructions.
@Look here for more details:
.align 2
.global _start
mov r0, #1 @ stdout
adrl r1, hello
mov r2, #12 @ string length
swi #0x900004 @ sys_write
mov r0, #0 @ return code
swi #0x900001 @ sys_exit
.string "hello world\n"

Compile this with: whatever-prefix-as -o helloworld.o helloworld.s
whatever-prefix-ld -o helloworld helloworld.o
whatever-prefix-strip -s -x helloworld

The finished executable takes about 380 bytes here. Not too bad.
This became much longer than anticipated, but I feel I haven't said enough on the topic. Stay tuned for a part 2. Have fun! :-)
P.S I'm on #chat @ if you need some help.