ARM Assembler for iOS: Part 1 – Environment Setup
A few weeks ago I came into the need of optimizing some OpenGL code for iOS. There was alot of matrix- and vector-calculations going on that could greatly be improved by taking advantage of the NEON coprocessor found in every of the newer iPhone and iPad versions. It is a vector-based processor also allowing single-precission float-point calculations. Taking advantage of this processor for OpenGL applications can make a signification difference as you often do vector-based floating-point calculations. Nicely, there already exist a library that provides all that is needed regarding vector- and matrix-opertions and leverages the NEON chip by implementing the main functionality directly in assembly code (you are not able to directly access that coprocessor from your C-code). My only problem: I always like to understand what I am doing and would even sometimes rather re-implement some library myself then blindly reusing something I don’t understand the inner-workings of. Not sure if this is a good quality or a bad one…
This led me to the goal for this series of posts: Learn assembly for the ARM chip, which is found in all of the iOS-powered devices by Apple (and also in most other phones that play in the same league as the iPhone). I will try to write down my experience and the learned stuff within this series to help others getting started as well. For this, I will heavily rely on external resources like documentations, blog-posts and tutorials. This “diary” will function as the glue that holds everything together and makes me stick with my set goal to learn ARM assembly.
In this parts of the series we will focus on setting up the environment and make sure that our tool-chain is working. Namely, we will do the following:
- Install the GNU ARM Assembler toolchain
- Build a first Hello-World C-application that we will compile, run and debug with the installed toolchain
Lets get started!
Installing the GNU ARM toolchain
As the iOS applications compiled for the iPhone Simulator are translated to normal x68 code (the simulator does not simulate an ARM chip) we cannot just write assembly code in your iOS project and run it in the simulator. For sure, we don’t want to connect an iOS device for our early fiddling with the ARM chip. Thus we will install the GNU ARM Assembler tool-chain which is free and comes with a simulator that allows us to run the developed code without a real device.
Go to the GNU ARM webpage and download the binary for your architecture. As I am focusing on Apple mobile devices, i assume you will download the toolchain for Mac OSX.
After unpacking and installing the download, you should have the following tools installed, that you are able to call from you command-line shell
- arm-elf-gcc The gcc compiler to build executables
- arm-elf-run To run executables
- arm-elf-gdb The debugger to debug built executables
- arm-elf-objdump To disassemble/read out sections of the library
As you might notice, these are all the standard binutils you already know. They only support (and compile for) the ARM architecture, but if you are familiar with gcc, gdb, etc, you should have no big problems with these tools.
The only small negative point is that these tools build and run ELF-based executables and not the Mach-O executables known from Mac OSX and iOS. So, you will have to use objdump here, but use otool for example on your iOS executables. But it is not really justified to make such a complaint…
Building a simple Hello-World App for the ARM chip
Lets build a very simple Hello-World app. We will compile, link, run and debug that app with the just installed tools.
Create a helloworld.c file with the following content:
You can see that the file only prints out “hello world” and has a simple stub for adding some assembly-code to playing around with the ARM-specifics. The “mov r0,r0”, is basically a no-op and we don’t worry about it for now.
Perform the following set of calls to build, link and run the executable (named “hw”):
There should be no problems with these steps and running the “hw” exectuable should actually print “hello world” to the commandline; but I just also want to show you how to start the executable in the debugger:
You see, it requires first to call “file hw”, to load the executable, “target sim”, then “load” and finally “run” to run the executable. All further commands, like setting break-points and stepping through the code is standard gdb and you can look it up in any regular tutorial on this toolchain (you can already do alot with break, stepi, nexti, continue, list and print).
Do you remember the “mov r0,r0” assembly instruction in our code? We can use “arm-elf-objdump -d hw” to actually disassembly the executable and see it listed as a “nop”:
Congratulations! You have successfully installed the tool-chain and are now ready to fiddle around with ARM assembly.
As a homework for the next part of the series, i will assume you have a look at the following really great resources:
The first tutorial was originally written for the Gameboy Advanced, but that should not confuse you. The GBA also uses an ARM7-chip and thus we can transfer almost all of the learned to our iOS devices.
You actually might wamt to play around a little with what you learn in the tutorial. Do you remember the “asm volatile” block in your main-method? You could use it to put some simple assembler code in and just play around. Details on how to pass and return back C-based variables to/from this inline-code, can be found in this very well-written blog-post. I don’t assume you go through it in every detail (we will come back to it later), but it will help you if you want to pass values between C- and assembly-code and not have to worry about call-conventions between C- and assembly-code too much. Actually, this will be the topic in Part 2 or 3 of the series.