ARM Assembly Programming Using Raspberry Pi GUI PDF
ARM Assembly Programming Using Raspberry Pi GUI PDF
Raspberry Pi
1 Introduction
The Raspberry Pi is an inexpensive credit-card sized Linux computer. At its core is an ARMv6 CPU. The
free download Raspbian package (from NOOBS http://www.raspberrypi.org/help/noobs-setup/)
contains all the software necessary for ARM assembly language programming.
The downloaded package includes Raspbian operating system and several programming language
supports. Among them is the GNU Compiler Collection (GCC) which supports programming in C, C++ and
assembly languages.
In this document, we will use the commands as (assembler), ld (link loader), and gdb (GNU debugger)
from GCC. These are command of command line interface that can be executed from the command
prompt. If you are using the graphic user interface (GUI), the command prompt is available from
LXTerminal which is part of the Raspbian software package.
We will assume the reader is comfortable using the command line interface of the Raspberry Pi. The
Raspbian software package comes with two command line text editors: nano editor and vi that may be
used to enter and edit the assembly source code. If you prefer to use a GUI text editor, Leafpad is
available. For more text editor options , please visit
http://www.raspberrypi.org/documentation/linux/usage/text-editors.md
Lastly, the screenshots in this document were captured remotely using Tera Term terminal emulator.
The content should look identical to the console display of the Raspberry Pi.
Below are the versions of the assembler and linker used in this document.
2 The Differences
The example programs in the book were developed using Keil MDK-ARM and uVision IDE. These
programs are intended to be stand-alone programs in an embedded ARM microcontroller. Programs
developed using GCC tools in Raspberry Pi are applications running under the Raspbian OS. Here are
some of the major differences:
1 of 23
1. The code and data of the program are all loaded in the RAM allocated by the OS using virtual
memory addressing. The virtual memory address is the address that the program sees. From a
programmer’s perspective, it should make no difference unless you are attempting to
read/write the hardware registers.
2. The program is running under Raspbian OS. The OS provides services such as console read/write
or file I/O.
3. The syntax for the assembly source file is different. GCC was developed to support many
different processors. With the recent version of GCC assembler (v2.24), ARM instructions are
kept the same as Keil MDK-ARM, the other parts of the syntax are slightly different.
a. Comments are preceded by ‘@’ instead of ‘;’. The assembler also accepts C++ style
comment enclosed with ‘/* */’ and ‘//’.
b. Labels must be followed by a ‘:’.
c. The syntaxes of the directives are different but the mappings are straightforward. Below
is a comparison table of the frequently used directives:
2 of 23
Program 2-1 Using Keil MDK-ARM syntax
; ARM Assembly Language Program To Add Some Data and Store the SUM in R3.
.global _start
_start: MOV R1, #0x25 @ R1 = 0x25
MOV R2, #0x34 @ R2 = 0x34
ADD R3, R2, R1 @ R3 = R2 + R1
HERE: B HERE @ stay here forever
Technically the code of the program is marked by .text directive at the beginning and the end of the
program should have the directive “.end”. However, GCC does not enforce either one.
First we make a directory with the name asm, change the current directory to asm and launch the editor
vi for the file p2_1.s. We are showing the use of editor vi here but you may use any text editor you
prefer.
3 of 23
Figure 2: make asm directory, change to asm directory and launch editor vi
The program is assembled using command “as –o p2_1.o p2_1.s”. In this command, “as” is the
name of the assembler, “–o p2_1.o” tells the assembler to create the output object file with the name
p2_1.o, and lastly, “p2_1.s” is the assembly source file name (see below).
Like many Unix1 programs, it produces no output to the console when the program ran without errors.
1
Raspbian is ported from Debian which derived from Linux and Linux is derived from Unix. All of them are very
similar. In this document we will use Unix as a generic term for these operating system.
4 of 23
Linker takes one or more object files and creates an executable file. To run the linker, use command
“ld –o p2_1 p2_1.o”. In this command, “ld” is the name of the linker program, “–o p2_1” tells the
linker to produce the output executable file with the name p2_1, and lastly, “p2_1.o” is the input
object file name.
Again, the linker produces no output to the console when there were no errors.
To execute the program, type the command “./p2_1” at the prompt. It tells the shell to execute the
program named p2_1 at the current directory.
Recall the last instruction in the program is an infinite loop. After executing the first three instructions,
the program is stuck at the infinite loop that consumes 100% of the CPU time. An infinite loop is typical
for a program in a simple embedded system without an operating system. For now, type Ctrl-C to
terminate the program and get the prompt back.
5 Program Termination
As an application running under a multitasking operating system, the program should be terminated
when done. Otherwise, the program running a dummy infinite loop will consume the CPU time and slow
down all the other programs.
To terminate a program, replace the dummy infinite loop at the end of the program “HERE: B HERE”
by:
MOV R7, #1
SVC 0
5 of 23
The number 1 placed in Register 7 tells the operating system to terminate this program. The instruction
“SVC 0” is the system call, that transfers the program execution to the operating system. If you place
a different number in R7, the operating system will perform a difference service. We will visit a system
call to write to the console later.
After replacing the dummy infinite loop with the system call to end the program, run the assembler and
linker again. This time after you execute the program, the program will terminate by itself and the
prompt reappears immediately without user intervention.
6 Using GDB
A computer without output is not very interesting like the previous example program. We will see how
to generate output from a program in the next section, but for most of the programs in this book, they
demonstrate the manipulations of data between CPU registers and memory without any output. GDB
(GNU Debugger) is a great tool to use to study the assembly programs. You can use GDB to step through
the program and examine the contents of the registers and memory.
In the following example, we will demonstrate how to control the execution of the program using GDB
and examine the register and memory content.
$ as -g -o p2_1.o p2_1.s
$ ld -o p2_1 p2_1.o
To launch the GNU Debugger, type the command gdb followed by the executable file name at the
prompt:
$ gdb p2_1
After displaying the license and warranty statements, the prompt is shown as (gdb). See Figure 8 below.
6 of 23
Figure 8: assemble with debug option and launch of gdb
To list the source code, the command is “list”. The list command displays 10 lines of the source code
with the line number in front of each line. To see the next 10 lines, just hit the Enter key.
Figure 9: use gdb command list to display source code with line number
7 of 23
“break” followed by line number. The following command sets a breakpoint at line 6 of the program.
When we run the program, the program execution will stop right before line 6 is executed.
$ b 6
8 of 23
Figure 12: display register contents using info register command
In the disassembled display, the breakpoint instruction is marked by an arrow at the left margin.
The disassemble command also takes a pair of starting address and ending address separated by a
comma such as:
Note in the example in Figure 14 that although the last instruction of the program is at address
0x00008060, the disassembled output continued until the specified address was met.
9 of 23
Figure 14: disassemble the machine code between address 0x8054 and 0x806C
In the example below in Figure 15, we stepped two instructions and examined the register contents.
Figure 15: step instruction twice and examine the register content
In this example as seem in Figure 16, if we continue program execution and there are no more
breakpoints left, the program will run without stopping and we have no gdb prompt to issue a command.
To stop program execution, hit Ctrl-C.
10 of 23
Options Possible values
Number of items any number
Format octal, hex, decimal, unsigned decimal, bit, float,
address, instruction, char, and string
Size byte, halfword, word, giant (8-byte)
For the example in Figure 1Figure 17 to display eight words in hexadecimal starting at location 0x8054,
the command is “x/8xw 0x8054”.
7 Floating Point
The Raspberry Pi has hardware floating point support (VFP). You may write 32-bit or 64-bit floating point
instructions in the assembly program.
To assemble a program with floating point instructions, you need to let the assembler know that you are
using the VFP instructions by adding the command line option “-mfpu=vfp”. A sample command will be:
In GDB, you may examine the VFP registers using command “info float”. The registers are displayed
in 64-bit mode and 32-bit mode with floating point output and hexadecimal output. The content of the
VFP status register fpscr is also displayed.
8 Program Output
Using the last sample program, we will send the result of the addition to output. We do so by placing
the result in R0 before making the exit system call. The end of the program will look like this:
MOV R0, R3
11 of 23
MOV R7, #1
SVC 0
After the program exit, at the prompt type command “echo $?” and the result 89 (decimal) will be
displayed.
Code::Blocks (http://www.codeblocks.org/) is an open source C, C++ and Fortran IDE licensed under the
term of GNU General Public License version 3. Although Code::Blocks is not intended for assembly
language programming, with GNU GCC compiler and GNU GDB debugger plug-ins, it can handle
assembly language programming.
Code::Blocks IDE does not support an assembly language only project so we need to start a C project
then replace the “main.c” with an assembly language source file. (I will support a project with both C
language source files and assembly language source files but that is beyond the scope of this document.)
As a C language project, the C start-up code will be automatically linked into the executable code but
this will be mostly transparent to the assembly programmer (or C programmer for that matter). We will
describe the differences it causes later.
You do need Internet connection to download and install the software package and it will take several
minutes to complete.
12 of 23
9.2 Start Code::Blocks IDE
To start the Code::Blocks IDE, click the start button (at the lower left corner of the Desktop), select
Programming then Code::Blocks IDE. (To bring up the Desktop from command line interface, type
command “startx”.)
The first time you launch Code::Blocks IDE, it will ask you to confirm the compiler plug-ins. Unless you
have installed other compiler tools, it should detect only the GNU GCC compiler.
Keep the default wizard type as “Project” and click select “Console application” wizard then click the “Go”
button (see Figure 20).
13 of 23
Figure 20: create a new project using “Console application” wizard
The window will be replaced by “Console application” wizard. First it will ask for the selection of
programming language. Select “C” then click “Next>” button (See Figure 21).
14 of 23
Figure 21: select C language for the project
The next window asks for the project title and the folder where the project will be created. The wizard
creates a folder with the project name under the folder you specified and put all the project files and
folders in it. For example, we selected a folder “/home/pi/asm” and a project title “p2_1” (See Figure
22). A folder “/home/pi/asm/p2_1” will be created and all the files and folders of this project will be
placed in it.
Click “Next>” button and the next window is used to select compiler and configuration. Take the default
selections as in Figure 23 then click “Finish” button.
15 of 23
Figure 23: select compiler and configurations
Expand the project tree in the left panel and right click on “main.c” then select “Remove file from
project” (See Figure 24).
Now, add an empty file to the project from menu File->New->Empty file (See Figure 25).
16 of 23
Figure 25: add an empty file to the project
Click “Yes” button to confirm adding this file to the project (See Figure 26).
In order to add a file to the project, the file needs to be saved. The “Save file” window will pop up. Enter
a file name (for example, p2_1.s) and click “Save” button (See ). The file needs an extension of “.s” to be
recognized as an assembly language source file.
17 of 23
Figure 27: save the file with a file name
The next window pops up will ask you to select the targets for this file (See Figure 28). Make sure
“Debug” is selected before clicking on the “Ok” button.
Once the empty file is added to the project, we may type in the code. We will reuse the program
example from the early command line interface with a small change.
18 of 23
Program 2-1g Using GCC as version 2.24 syntax
@P2_1.s ARM Assembly Language Program To Add Some Data and Store the SUM in R3.
.global main
main: MOV R1, #0x25 @ R1 = 0x25
MOV R2, #0x34 @ R2 = 0x34
ADD R3, R2, R1 @ R3 = R2 + R1
HERE: B HERE @ stay here forever
Recall the GCC linker is expecting a label “_start” as the entry point of the program. That’s why we used
it in the previous program. The difference here is that we are borrowing a C language project for our
assembly program. When GCC is linking a C program, it includes the C startup code at the beginning of
the program. The C startup code has the label “_start” as the entry point and the program execution
starts there. At the end of the C startup code, the program branches to a label “main” so we need to use
“main” as the label of the entry point of our program.
Figure 29: click "Build" button to assemble and link the program
The “Build log” window will show at the lower part of the window. Make sure there are no errors nor
warnings (See Figure 30).
19 of 23
number in the source editor window and a red stop sign will show. To remove a breakpoint, click on the
red stop sign and the breakpoint will be removed.
With the breakpoint set, click “Debug / Continue” button to launch the debugger (See Figure 31).
The debugger changes the perspective of IDE then run the program until a breakpoint is hit. In our
program with the breakpoint on line 5, the program executes until right before the instruction on line 5
is executed.
Figure 32: the debugger stops before the breakpoint line is executed
From Figure 32 above, you may see that there is a yellow triangle superimposed on the stop sign on line
5 denotes that the program execution is halted and the program counter is pointing to the instruction
on line 5. The same is shown in the Disassembly window. The CPU Register window shows that r1 has
the content of 0x25 as the result of the instruction on line 4.
20 of 23
If Register window or Disassembly window is not visible, you may enable them from menu
“Debug->Debugging windows”.
When the “Next instruction” button is pressed, the yellow arrow moves to the next instruction (line 6 in
Figure 34). Also as the result of instruction on line 5, register r2 has the content changed to 0x34..
21 of 23
Figure 35: enable Examine memory window
22 of 23
Bear in mind, the information displays are modal (when one of them is opened, you may not interact
with the debugger until it is closed).
10 Conclusion
This document described how to use GCC tools to write assembly programs in a Raspberry Pi. It also
discussed the use of GDB debugger. Lastly, the use of Code::Blocks IDE as the GUI is introduced.
23 of 23