5.6.1. Direct loading with ADR and ADRL

The ADR and ADRL pseudo-instructions enable you to load a range of addresses without performing a memory access. ADR and ADRL accept either:

The assembler converts an ADR rn,label pseudo-instruction by generating:

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.

The assembler converts an ADRL rn,label pseudo-instruction by generating:

The range of an ADRL pseudo-instruction is 64KB for a non-word aligned address and 256KB for a word-aligned address.

ADRL assembles to two instructions, if successful. The assembler generates two instructions even if the address could be loaded in a single instruction.

Refer to Loading addresses with LDR Rd, = label for information on loading addresses that are outside the range of the ADRL pseudo-instruction.

Note

  • The label used with ADR or ADRL must be within the same code area. There is no guarantee that the label will be within range after linking if it is defined in a different area. The assembler can only fault references to labels that are out of range in the same area.

  • In Thumb state, ADR can generate word-aligned addresses only.

  • ADRL is not available in Thumb code. Use it only in ARM code.

Example 5.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 examples\asm subdirectory of the toolkit. Refer to Code examples for instructions on how to assemble, link, and execute the example.

The instructions listed in the comments are the ARM instructions generated by the assembler.

Example 5.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					; Angel semihosting ARM 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 		r3, DataArea+4300					; => ADD r2, PC, #offset1
										;  ADD r2, r2, #offset2
			MOV		pc, lr					; Return
DataArea			% 		8000					; Starting at the current location, 
										; clears a 8000 byte area of memory
										; to zero.
			END

Implementing a jump table with ADR

Example 5.7 shows ARM code that implements a jump table. It is supplied as jump.s in the examples\asm subdirectory of the toolkit. Refer to Code examples for instructions on how to assemble, link, and execute the example.

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:

argument1=0

Result = argument2 + argument3

argument1=1

Result = argument2 – argument3

argument1>1

the same as argument1=0.

The jump table is implemented with the following instructions and assembler directives:

EQU

is an assembler directive. It is used to give a value to a symbol. In this example it assigns the value 2 to num. When num is used elsewhere in the code, the value 2 is substituted. Using EQU in this way is similar to using #define to define a constant in C.

DCD

declares 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.

LDR

The 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 5.7. 

		AREA 		Jump, CODE, READONLY						; Name this block of 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						; Angel semihosting ARM SWI
arithfunc										; Label the function.
		CMP		r0, #num						; Treat function code as unsigned
										; integer.
		BHS		DoAdd						; If code is >=2 then do operation 0.
		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, >1
		MOV	 	pc, lr						; Return
DoSub		SUB		r0, r1, r2						; Operation 1
		MOV		pc,lr						; Return
		END								; Mark the end of this file.

Converting to Thumb

To convert Example 5.7 to Thumb code you must modify the LDR instruction that is used to implement the jump. This is because you cannot increment the base register of LDR and STR instructions in Thumb state. In addition, LDR cannot load a value into the pc, or do an inline shift of a value held in a register.

The equivalent code to cause the jump to the appropriate routine is:

		LSL		r0, r0,#2
		LDR		r3, [r3,r0]
		MOV		pc, r3

You must place an ALIGN directive before the Jumptable label to ensure that the table is aligned on a 32-bit boundary.

Copyright © 1997, 1998 ARM Limited. All rights reserved.ARM DUI 0040D
Non-Confidential