The following changes have been made to this book.
Change History
DateIssueChange
November 2000ARelease 1.1
November 2001BRelease 1.2
Proprietary Notice
Words and logos marked with
brands and names mentioned herein may be the trademarks of their respective owners.
Neither the whole nor any part of the information contained in, or the product described in, this document
may be adapted or reproduced in any material form except with the prior written permission of the copyright
holder.
®
or ™ are registered trademarks or trademarks owned by ARM Limited. Other
The product described in this document is subject to continuous developments and improvements. All
particulars of the product and its use contained in this document are given by ARM in good faith. However,
all warranties implied or expressed, including but not limited to implied warranties of merchantability, or
fitness for purpose, are excluded.
This document is intended only to assist the reader in the use of the product. ARM Limited shall not be liable
for any loss or damage arising from the use of any information in this document, or any error or omission in
such information, or any incorrect use of the product.
This book provides tutorial and reference information for the ADS assemblers (
armasm
the free-standing assembler, and inline assemblers in the C and C++ compilers). It
describes the command-line options to the assembler, the pseudo-instructions and
directives available to assembly language programmers, and the ARM, Thumb
®
, and
Vector Floating-point (VFP) instruction sets.
This book is written for all developers who are producing applications using ADS. It
assumes that you are an experienced software developer and that you are familiar with
the ARM development tools as described in ADS Getting Started.
This book is organized into the following chapters:
Chapter 1 Introduction
Read this chapter for an introduction to the ADS version 1.2 assemblers
and assembly language.
Chapter 2 Writing ARM and Thumb Assembly Language
Read this chapter for tutorial information to help you use the ARM
assemblers and assembly language.
Chapter 3 Assembler Reference
Read this chapter for reference material about the syntax and structure of
the language provided by the ARM assemblers.
,
Chapter 4 ARM Instruction Reference
Read this chapter for reference material on the ARM instruction set.
Chapter 5 Thumb Instruction Reference
Read this chapter for reference material on the Thumb instruction set.
Chapter 6 Vector Floating-point Programming
Read this chapter for reference material on the VFP instruction set, and
other VFP-specific assembly language information.
Chapter 7 Directives Reference
Read this chapter for reference material on the assembler directives
available in the ARM assembler,
The following typographical conventions are used in this book:
Preface
Further reading
monospace
Denotes text that can be entered at the keyboard, such as commands, file
and program names, and source code.
monospace
Denotes a permitted abbreviation for a command or option. The
underlined text can be entered instead of the full command or option
name.
monospace italic
Denotes arguments to commands and functions where the argument is to
be replaced by a specific value.
monospace bold
Denotes language keywords when used outside example code.
italicHighlights important notes, introduces special terminology, denotes
internal cross-references, and citations.
boldHighlights interface elements, such as menu names. Also used for
emphasis in descriptive lists, where appropriate, and for ARM processor
signal names.
This section lists publications from both ARM Limited and third parties that provide
additional information on developing code for the ARM family of processors.
ARM periodically provides updates and corrections to its documentation. See
http://www.arm.com
for current errata sheets and addenda.
See also the ARM Frequently Asked Questions list at:
http://www.arm.com/DevSupp/Sales+Support/faq.html
ARM publications
This book contains reference information that is specific to development tools supplied
with ADS. Other publications included in the suite are:
•ADS Installation and License Management Guide (ARM DUI 0139)
•an optimizing inline assembler built into the C and C++ compilers.
The language that these assemblers take as input is basically the same. However, there
are limitations on what features of the language you can use in the inline assemblers.
Refer to the Mixing C, C++, and Assembly Language chapter in ADS Developer Guide
for further information on the inline assemblers.
This chapter gives a basic, practical understanding of how to write ARM and Thumb
assembly language modules. It also gives information on the facilities provided by the
ARM assembler (armasm).
This chapter does not provide a detailed description of the ARM, Thumb, or VFP
instruction sets. This information can be found in Chapter 4 ARM Instruction
Reference, Chapter 5 Thumb Instruction Reference, and Chapter 6 Vect or
Floating-point Programming. Further information can be found in ARM Architecture
Reference Manual.
2.1.1Code examples
There are a number of code examples in this chapter. Many of them are supplied in the
examples\asm
Follow these steps to build, link, and execute an assembly language file:
directory of the ADS.
1.Type
armasm -g filename.s
at the command prompt to assemble the file and
generate debug tables.
2.Type
armlink filename.o -o filename
to link the object file and generate an ELF
executable image.
3.Type
4.Type
5.Type
armsd filename
go
at the
armsd:
quit
at the
armsd:
to load the image file into the debugger.
prompt to execute it.
prompt to return to the command line.
To see how the assembler converts the source code, enter:
fromelf -text/c filename.o
or run the module in AXD with interleaving on.
See:
•AXD and armsd Debuggers Guide for details on armsd, and AXD.
This section gives a brief overview of the ARM architecture.
ARM processors are typical of RISC processors in that they implement a load/store
architecture. Only load and store instructions can access memory. Data processing
instructions operate on register contents only.
2.2.1Architecture versions
The information and examples in this book assume that you are using a processor that
implements ARM architecture v3 or above. See ARM Architecture Reference Manual
for details of the various architecture versions.
All these processors have a 32-bit addressing range.
2.2.2ARM and Thumb state
ARM architecture versions v4T and above define a 16-bit instruction set called the
Thumb instruction set. The functionality of the Thumb instruction set is a subset of the
functionality of the 32-bit ARM instruction set. Refer to Thumb instruction set overview
on page 2-9 for more information.
Writing ARM and Thumb Assembly Language
A processor that is executing Thumb instructions is operating in Thumb state. A
processor that is executing ARM instructions is operating in ARM state.
A processor in ARM state cannot execute Thumb instructions, and a processor in
Thumb state cannot execute ARM instructions. You must ensure that the processor
never receives instructions of the wrong instruction set for the current state.
Each instruction set includes instructions to change processor state.
You must also switch the assembler mode to produce the correct opcodes using
and
CODE32
directives. Refer to CODE16 and CODE32 on page 7-54 for details.
CODE16
ARM processors always start executing code in ARM state.
ARM processors support up to seven processor modes, depending on the architecture
version. These are:
•User
•FIQ - Fast Interrupt Request
•IRQ - Interrupt Request
•Supervisor
•Abort
•Undefined
•System (ARM architecture v4 and above).
All modes except User mode are referred to as privileged modes.
Applications that require task protection usually execute in User mode. Some
embedded applications might run entirely in Supervisor or System modes.
Modes other than User mode are entered to service exceptions, or to access privileged
resources. Refer to the Handling Processor Exceptions chapter in ADS Developer Guide, and ARM Architecture Reference Manual for more information.
2.2.4Registers
ARM processors have 37 registers. The registers are arranged in partially overlapping
banks. There is a different register bank for each processor mode. The banked registers
give rapid context switching for dealing with processor exceptions and privileged
operations. Refer to ARM Architecture Reference Manual for a detailed description of
how registers are banked.
The following registers are available in ARM architecture v3 and above:
•30 general-purpose, 32-bit registers
•The program counter (pc) on page 2-5
•The Current Program Status Register (CPSR) on page 2-5
•Five Saved Program Status Registers (SPSRs) on page 2-5.
30 general-purpose, 32-bit registers
Fifteen general-purpose registers are visible at any one time, depending on the current
processor mode, as r0, r1, ... ,r13, r14.
By convention, r13 is used as a stack pointer (sp) in ARM assembly language. The C
and C++ compilers always use r13 as the stack pointer.
In User mode, r14 is used as a link register (lr) to store the return address when a
subroutine call is made. It can also be used as a general-purpose register if the return
address is stored on the stack.
In the exception handling modes, r14 holds the return address for the exception, or a
subroutine return address if subroutine calls are executed within an exception. r14 can
be used as a general-purpose register if the return address is stored on the stack.
The program counter (pc)
The program counter is accessed as r15 (or pc). It is incremented by one word (four
bytes) for each instruction in ARM state, or by two bytes in Thumb state. Branch
instructions load the destination address into the program counter. You can also load the
program counter directly using data operation instructions. For example, to return from
a subroutine, you can copy the link register into the program counter using:
MOV pc,lr
During execution, r15 does not contain the address of the currently executing
instruction. The address of the currently executing instruction is typically pc–8 for
ARM, or pc–4 for Thumb.
The Current Program Status Register (CPSR)
The CPSR holds:
•copies of the Arithmetic Logic Unit (ALU) status flags
•the current processor mode
•interrupt disable flags.
The ALU status flags in the CPSR are used to determine whether conditional
instructions are executed or not. Refer to Conditional execution on page 2-20 for more
information.
On Thumb-capable processors, the CPSR also holds the current processor state (ARM
or Thumb).
On ARM architecture v5TE, the CPSR also holds the Q flag (see The ALU status flags
on page 2-20).
Five Saved Program Status Registers (SPSRs)
The SPSRs are used to store the CPSR when an exception is taken. One SPSR is
accessible in each of the exception-handling modes. User mode and System mode do
not have an SPSR because they are not exception handling modes. Refer to the
Handling Processor Exceptions chapter in ADS Developer Guide for more information.
All ARM instructions are 32 bits long. Instructions are stored word-aligned, so the least
significant two bits of instruction addresses are always zero in ARM state. Some
instructions use the least significant bit to determine whether the code being branched
to is Thumb code or ARM code.
See Chapter 4 ARM Instruction Reference for detailed information on the syntax of the
ARM instruction set.
ARM instructions can be classified into a number of functional groups:
•Branch instructions
•Data processing instructions
•Single register load and store instructions on page 2-7
•Multiple register load and store instructions on page 2-7
•Status register access instructions on page 2-7
•Semaphore instructions on page 2-7
•Coprocessor instructions on page 2-7.
Branch instructions
These instructions are used to:
•branch backwards to form loops
•branch forward in conditional structures
•branch to subroutines
•change the processor from ARM state to Thumb state.
Data processing instructions
These instructions operate on the general-purpose registers. They can perform
operations such as addition, subtraction, or bitwise logic on the contents of two registers
and place the result in a third register. They can also operate on the value in a single
register, or on a value in a register and a constant supplied within the instruction (an
immediate value).
Long multiply instructions (unavailable in some architectures) give a 64-bit result in
two registers.
These instructions load or store the value of a single register from or to memory. They
can load or store a 32-bit word or an 8-bit unsigned byte. In ARM architecture v4 and
above they can also load or store a 16-bit unsigned halfword, or load and sign extend a
16-bit halfword or an 8-bit byte.
Multiple register load and store instructions
These instructions load or store any subset of the general-purpose registers from or to
memory. Refer to Load and store multiple register instructions on page 2-39 for a
detailed description of these instructions.
Status register access instructions
These instructions move the contents of the CPSR or an SPSR to or from a
general-purpose register.
Semaphore instructions
These instructions load and alter a memory semaphore.
Coprocessor instructions
These instructions support a general way to extend the ARM architecture.
The following general points apply to ARM instructions:
•Conditional execution
•Register access
•Access to the inline barrel shifter.
Conditional execution
Almost all ARM instructions can be executed conditionally on the value of the ALU
status flags in the CPSR. You do not need to use branches to skip conditional
instructions, although it can be better to do so when a series of instructions depend on
the same condition.
You can specify whether a data processing instruction sets the state of these flags or not.
You can use the flags set by one instruction to control execution of other instructions
even if there are many instructions in between.
Refer to Conditional execution on page 2-20 for a detailed description.
Register access
In ARM state, all instructions can access r0 to r14, and most also allow access to r15
(pc). The
MRS
and
MSR
instructions can move the contents of the CPSR and SPSRs to a
general-purpose register, where they can be manipulated by normal data processing
operations. Refer to MRS on page 4-73 and MSR on page 4-74 for more information.
Access to the inline barrel shifter
The ARM arithmetic logic unit has a 32-bit barrel shifter that is capable of shift and
rotate operations. The second operand to all ARM data-processing and single register
data-transfer instructions can be shifted, before the data-processing or data-transfer is
executed, as part of the instruction. This supports, but is not limited to:
•scaled addressing
•multiplication by a constant
•constructing constants.
Refer to Loading constants into registers on page 2-25 for more information on using
the barrel-shifter to generate constants.
The functionality of the Thumb instruction set is almost exactly a subset of the
functionality of the ARM instruction set. The instruction set is optimized for production
by a C or C++ compiler.
All Thumb instructions are 16 bits long and are stored halfword-aligned in memory.
Because of this, the least significant bit of the address of an instruction is always zero
in Thumb state. Some instructions use the least significant bit to determine whether the
code being branched to is Thumb code or ARM code.
All Thumb data processing instructions:
•operate on full 32-bit values in registers
•use full 32-bit addresses for data access and for instruction fetches.
Refer to Chapter 5 Thumb Instruction Reference for detailed information on the syntax
of the Thumb instruction set, and how Thumb instructions differ from their ARM
counterparts.
2.2.8Thumb instruction capabilities
The following general points apply to Thumb instructions:
•Conditional execution
•Register access
•Access to the barrel shifter on page 2-10.
Writing ARM and Thumb Assembly Language
Conditional execution
The conditional branch instruction is the only Thumb instruction that can be executed
conditionally on the value of the ALU status flags in the CPSR. All data processing
instructions update these flags, except when one or more high registers are specified as
operands to the
MOV
or
ADD
instructions. In these cases the flags cannot be updated.
You cannot have any data processing instructions between an instruction that sets a
condition and a conditional branch that depends on it. Use a conditional branch over any
instruction that you wish to be conditional.
Register access
In Thumb state, most instructions can access only r0 to r7. These are referred to as the
low registers.
Registers r8 to r15 are limited access registers. In Thumb state these are referred to as
high registers. They can be used, for example, as fast temporary storage.
Refer to Chapter 5 Thumb Instruction Reference for a complete list of the Thumb data
processing instructions that can access the high registers.
Access to the barrel shifter
In Thumb state you can use the barrel shifter only in a separate operation, using an
LSR, ASR,
or
ROR
instruction.
2.2.9Differences between Thumb and ARM instruction sets
The general differences between the Thumb instruction set and the ARM instruction set
are dealt with under the following headings:
•Branch instructions
•Data processing instructions
•Single register load and store instructions on page 2-11
•Multiple register load and store instructions on page 2-11.
There are no Thumb coprocessor instructions, no Thumb semaphore instructions, and
no Thumb instructions to access the CPSR or SPSR.
Branch instructions
LSL
,
These instructions are used to:
•branch backwards to form loops
•branch forward in conditional structures
•branch to subroutines
•change the processor from Thumb state to ARM state.
Program-relative branches, particularly conditional branches, are more limited in range
than in ARM code, and branches to subroutines can only be unconditional.
Data processing instructions
These operate on the general-purpose registers. In many cases, the result of the
operation must be put in one of the operand registers, not in a third register. There are
fewer data processing operations available than in ARM state. They have limited access
to registers r8 to r15.
The ALU status flags in the CPSR are always updated by these instructions except when
MOV
or
ADD
instructions access registers r8 to r15. Thumb data processing instructions
that access registers r8 to r15 cannot update the flags.
Instructions, pseudo-instructions, and directives must be preceded by white space, such
as a space or a tab, even if there is no label.
All three sections of the source line are optional. You can use blank lines to make your
code more readable.
Case rules
Instruction mnemonics, directives, and symbolic register names can be written in
uppercase or lowercase, but not mixed.
armasm
) parses and
Line length
To make source files easier to read, a long line of source can be split onto several lines
by placing a backslash character ( \ ) at the end of the line. The backslash must not be
followed by any other characters (including spaces and tabs). The backslash/end-of-line
sequence is treated by the assembler as white space.
Note
Do not use the backslash/end-of-line sequence within quoted strings.
The exact limit on the length of lines, including any extensions using backslashes,
depends on the contents of the line, but is generally between 128 and 255 characters.
Labels are symbols that represent addresses. The address given by a label is calculated
during assembly.
The assembler calculates the address of a label relative to the origin of the section where
the label is defined. A reference to a label within the same section can use the program
counter plus or minus an offset. This is called program-relative addressing.
Labels can be defined in a map. See Describing data structures with MAP and FIELD directives on page 2-51. You can place the origin of the map in a specified register at
runtime, and references to the label use the specified register plus an offset. This is
called register-relative addressing.
Addresses of labels in other sections are calculated at link time, when the linker has
allocated specific locations in memory for each section.
Local labels
Local labels are a subclass of label. A local label begins with a number in the range
0-99. Unlike other labels, a local label can be defined many times. Local labels are
useful when you are generating labels with a macro. When the assembler finds a
reference to a local label, it links it to a nearby instance of the local label.
The scope of local labels is limited by the
AREA
directive. You can use the
ROUT
directive
to limit the scope more tightly.
Refer to the Local labels on page 3-16 for details of:
•the syntax of local label declarations
•how the assembler associates references to local labels with their labels.
Comments
The first semicolon on a line marks the beginning of a comment, except where the
semicolon appears inside a string constant. The end of the line is the end of the
comment. A comment alone is a valid line. All comments are ignored by the assembler.
Constants can be numeric, boolean, character or string:
Numbers Numeric constants are accepted in three forms:
Boolean The Boolean constants
Characters Character constants consist of opening and closing single quotes,
Strings Strings consist of opening and closing double quotes, enclosing
•Decimal, for example,
•Hexadecimal, for example,
•
n_xxx
where:
n
xxx
{FALSE}
.
is a base between 2 and 9
is a number in that base.
TRUE
123
and
0x7B
FALSE
must be written as
{TRUE}
and
enclosing either a single character or an escaped character, using the
standard C escape characters.
characters and spaces. If double quotes or dollar signs are used within a
string as literal text characters, they must be represented by a pair of the
appropriate character. For example, you must use
single
$
in the string. The standard C escape sequences can be used within
Example 2-1 illustrates some of the core constituents of an assembly language module.
The example is written in ARM assembly language. It is supplied as
examples\asm
subdirectory of ADS. Refer to Code examples on page 2-2 for instructions
on how to assemble, link, and execute the example.
The constituent parts of this example are described in more detail in the following
sections.
AREA ARMex, CODE, READONLY
; Name this block of code ARMex
ENTRY ; Mark first instruction to execute
start
MOV r0, #10 ; Set up parameters
MOV r1, #3
ADD r0, r0, r1 ; r0 = r0 + r1
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0x123456 ; ARM semihosting SWI
armex.s
Example 2-1
in the
END ; Mark end of file
ELF sections and the AREA directive
ELF sections are independent, named, indivisible sequences of code or data. A single
code section is the minimum required to produce an application.
The output of an assembly or compilation can include:
•One or more code sections. These are usually read-only sections.
•One or more data sections. These are usually read-write sections. They may be
zero initialized (ZI).
The linker places each section in a program image according to section placement rules.
Sections that are adjacent in source files are not necessarily adjacent in the application
image. Refer to the Linker chapter in ADS Linker and Utilities Guide for more
information on how the linker places sections.
In an ARM assembly language source file, the start of a section is marked by the
AREA
directive. This directive names the section and sets its attributes. The attributes are
placed after the name, separated by commas. Refer to AREA on page 7-52 for a detailed
description of the syntax of the
AREA
directive.
You can choose any name for your sections. However, names starting with any
nonalphabetic character must be enclosed in bars, or an
generated. For example:
|1_DataArea|
.
Example 2-1 on page 2-15 defines a single section called
is marked as being
READONLY
.
AREA name missing
ARMex
that contains code and
error is
The ENTRY directive
ENTRY
The
directive marks the first instruction to be executed. In applications containing
C code, an entry point is also contained within the C library initialization code.
Initialization code and exception handlers also contain entry points.
Application execution
The application code in Example 2-1 on page 2-15 begins executing at the label
start
where it loads the decimal values 10 and 3 into registers r0 and r1. These registers are
added together and the result placed in r0.
Application termination
,
After executing the main code, the application terminates by returning control to the
debugger. This is done using the ARM semihosting SWI (
0x123456 by default
), with
the following parameters:
•r0 equal to
•r1 equal to
angel_SWIreason_ReportException (0x18
ADP_Stopped_ApplicationExit (0x20026
)
).
Refer to the Semihosting SWIs chapter in ADS Debug Target Guide for additional
information.
The END directive
This directive instructs the assembler to stop processing this source file. Every assembly
To call subroutines, use a branch and link instruction. The syntax is:
BL destination
where
destination
is usually the label on the first instruction of the subroutine.
Writing ARM and Thumb Assembly Language
destination
can also be a program-relative or register-relative expression. Refer to B
and BL on page 4-58 for further information.
The
BL
instruction:
•places the return address in the link register (lr)
•sets pc to the address of the subroutine.
After the subroutine code is executed you can use a
MOV pc,lr
convention, registers r0 to r3 are used to pass parameters to subroutines, and to pass
results back to the callers.
Note
Calls between separately assembled or compiled modules must comply with the
restrictions and conventions defined by the procedure call standard. Refer to the Using the Procedure Call Standard in ADS Developer Guide for more information.
Example 2-2 shows a subroutine that adds the values of its two parameters and returns
a result in r0. It is supplied as
subrout.s
in the
examples\asm
to Code examples on page 2-2 for instructions on how to assemble, link, and execute the
example.
AREA subrout, CODE, READONLY
; Name this block of code
ENTRY ; Mark first instruction to execute
start MOV r0, #10 ; Set up parameters
MOV r1, #3
BL doadd ; Call subroutine
stop MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0x123456 ; ARM semihosting SWI
instruction to return. By
subdirectory of ADS. Refer
Example 2-2
doadd ADD r0, r0, r1 ; Subroutine code
MOV pc, lr ; Return from subroutine
END ; Mark end of file
Example 2-3 illustrates some of the core constituents of a Thumb assembly language
module. It is based on
subrout.s
. It is supplied as
thumbsub.s
in the
subdirectory of the ADS. Refer to Code examples on page 2-2 for instructions on how
to assemble, link, and execute the example.
AREA ThumbSub, CODE, READONLY ; Name this block of code
ENTRY ; Mark first instruction to execute
CODE32 ; Subsequent instructions are ARM
header ADR r0, start + 1 ; Processor starts in ARM state,
BX r0 ; so small ARM code header used
; to call Thumb main program
CODE16 ; Subsequent instructions are Thumb
start
MOV r0, #10 ; Set up parameters
MOV r1, #3
BL doadd ; Call subroutine
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0xAB ; Thumb semihosting SWI
doadd
ADD r0, r0, r1 ; Subroutine code
MOV pc, lr ; Return from subroutine
END ; Mark end of file
examples\asm
Example 2-3
CODE32 and CODE16 directives
These directives instruct the assembler to assemble subsequent instructions as ARM
CODE32
(
) or Thumb (
CODE16
) instructions. They do not assemble to an instruction to
change the processor state at runtime. They only change the assembler state.
The ARM assembler,
armasm
, starts in ARM mode by default. You can use the
-16
option
in the command line if you want it to start in Thumb mode.
BX instruction
This instruction is a branch that can change processor state at runtime. The least
significant bit of the target address specifies whether it is an ARM instruction (clear) or
ADR
a Thumb instruction (set). In this example, this bit is set in the