| |||
| Home > Writing ARM and Thumb Assembly Language > Loading addresses into registers > Direct loading with ADR and ADRL | |||
The ADR and ADRL pseudo-instructions
enable you to generate an address, within a certain range, without
performing a data load. ADR and ADRL accept
either of the following:
A program-relative expression, which is a label with an optional offset, where the address of the label is relative to the current pc.
A register-relative expression, which is a label with an optional offset, where the address of the label is relative to an address held in a specified general-purpose register. See Describing data structures with MAP and FIELD directives for information on specifying register-relative expressions.
The assembler converts an ADR r pseudo-instruction
by generating:n,label
a
single ADD or SUB instruction that loads
the address, if it is in range
an error message if the address cannot be reached in a single instruction.
The offset range is ±255 bytes for an offset to a non word-aligned address, and ±1020 bytes (255 words) for an offset to a word-aligned address. (For Thumb, the address must be word aligned, and the offset must be positive.)
The assembler converts an ADRL r pseudo-instruction
by generating:n,label
two data-processing instructions that load the address, if it is in range
an error message if the address cannot be constructed in two instructions.
The range of an ADRL pseudo-instruction is ±64KB
for a non word-aligned address and ±256KB for a word-aligned address.
(There is no ADRL pseudo-instruction for Thumb.)
ADRL assembles to two instructions, if successful.
The assembler generates two instructions even if the address could
be loaded in a single instruction.
See Loading addresses with
LDR Rd, = label for
information on loading addresses that are outside the range of the ADRL pseudo-instruction.
The label used with ADR or ADRL must
be within the same code section. The assembler faults references
to labels that are out of range in the same section. The linker
faults references to labels that are out of range in other code
sections.
In Thumb state, ADR can generate word-aligned
addresses only.
ADRL is not available in Thumb code. Use it only
in ARM code.
Example 2.6 shows the
type of code generated by the assembler when assembling ADR and ADRL pseudo-instructions.
It is supplied as adrlabel.s in the subdirectory
of the RVCT. See Code examples for instructions on how to assemble,
link, and execute the example.Examples_directory\asm
The instructions listed in the comments are the ARM instructions generated by the assembler.
Example 2.6.
AREA adrlabel, CODE,READONLY
ENTRY ; Mark first instruction to execute
Start
BL func ; Branch to subroutine
stop MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0x123456 ; ARM semihosting SWI
LTORG ; Create a literal pool
func ADR r0, Start ; => SUB r0, PC, #offset to Start
ADR r1, DataArea ; => ADD r1, PC, #offset to DataArea
; ADR r2, DataArea+4300 ; This would fail because the offset
; cannot be expressed by operand2
; of an ADD
ADRL r2, DataArea+4300 ; => ADD r2, PC, #offset1
; ADD r2, r2, #offset2
MOV pc, lr ; Return
DataArea SPACE 8000 ; Starting at the current location,
; clears a 8000 byte area of memory
; to zero
END
Example 2.7 shows
ARM code that implements a jump table. It is supplied as jump.s in
the subdirectory
of RVCT. See Code examples for
instructions on how to assemble, link, and execute the example.Examples_directory\asm
The ADR pseudo-instruction loads the address
of the jump table.
In the example, the function arithfunc takes
three arguments and returns a result in r0. The first argument determines
which operation is carried out on the second and third arguments:
Result = argument2 + argument3.
Result = argument2 – argument3.
The jump table is implemented with the following instructions and assembler directives:
EQUIs an assembler directive. It is used to give a
value to a symbol. In this example it assigns the value 2 to .
When num is used elsewhere
in the code, the value 2 is substituted. Using numEQU in
this way is similar to using #define to define
a constant in C.
DCDDeclares
one or more words of store. In this example each DCD stores
the address of a routine that handles a particular clause of the
jump table.
LDRThe LDR
pc,[r3,r0,LSL#2] instruction loads the address of the required clause
of the jump table into the pc. It:
multiplies the clause number in r0 by 4 to give a word offset
adds the result to the address of the jump table
loads the contents of the combined address into the program counter.
Example 2.7. ARM code jump table
AREA Jump, CODE, READONLY ; Name this block of code
CODE32 ; Following code is ARM code
num EQU 2 ; Number of entries in jump table
ENTRY ; Mark first instruction to execute
start ; First instruction to call
MOV r0, #0 ; Set up the three parameters
MOV r1, #3
MOV r2, #2
BL arithfunc ; Call the function
stop MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0x123456 ; ARM semihosting SWI
arithfunc ; Label the function
CMP r0, #num ; Treat function code as unsigned integer
MOVHS pc, lr ; If code is >= num then simply return
ADR r3, JumpTable ; Load address of jump table
LDR pc, [r3,r0,LSL#2] ; Jump to the appropriate routine
JumpTable
DCD DoAdd
DCD DoSub
DoAdd ADD r0, r1, r2 ; Operation 0
MOV pc, lr ; Return
DoSub SUB r0, r1, r2 ; Operation 1
MOV pc, lr ; Return
END ; Mark the end of this file
Example 2.8 shows the implementation of the jump table converted to Thumb code.
Most of the Thumb version is the same as the ARM code. The differences are commented in the Thumb version.
In Thumb state, you cannot:
increment the
base register of LDR and STR instructions
load a value into the pc using an LDR instruction
do an inline shift of a value held in a register.
Example 2.8. Thumb code jump table
AREA Jump, CODE, READONLY
CODE16 ; Following code is Thumb code
num EQU 2
ENTRY
start
MOV r0, #0
MOV r1, #3
MOV r2, #2
BL arithfunc
stop MOV r0, #0x18
LDR r1, =0x20026
SWI 0xAB ; Thumb semihosting SWI
arithfunc
CMP r0, #num
BHS exit ; MOV pc, lr cannot be conditional
ADR r3, JumpTable
LSL r0, r0, #2 ; 3 instructions needed to replace
LDR r0, [r3,r0] ; LDR pc, [r3,r0,LSL#2]
MOV pc, r0
ALIGN ; Ensure that the table is aligned on a
; 4-byte boundary
JumpTable
DCD DoAdd
DCD DoSub
DoAdd ADD r0, r1, r2
exit MOV pc, lr
DoSub SUB r0, r1, r2
MOV pc, lr
END