有这几种方式可以加载地址到寄存器:
- 使用ADR汇编指令
- 使用ADRL伪指令
- 使用MOV32伪指令
- 使用LDR Rd,=Label伪指令
下面介绍下ADR和DDRL这两个指令,另外两个前面的文章(ARM汇编中立即数的加载)已经有介绍过了不再重复详细介绍。
- ADR
功能:在特定范围之内把地址加载到寄存器(并不会执行数据加载)
语法格式如下:
ADR{cond}{.W} Rd,label
其中label是一个和PC相关的表达式,并且label相对当前指令有距离的限制。同时label和ADR必须同属于一个代码段。
下面是lable相对当前指令距离限制
指令 | 偏移范围 |
---|---|
A32 的ADR | 一个8位值的数旋转右移偶数个位(32位范围内的)来产生 |
T32 32位的ADR | ±4095 |
T32 16位的ADR | 0~1020(是4的倍数的才可以) |
下面是参考资料中的例子:
AREA Jump, CODE, READONLY ; Name this block of code
ARM ; Following code is A32 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 arguments
MOV r1, #3
MOV r2, #2
BL arithfunc ; Call the function
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
arithfunc ; Label the function
CMP r0, #num ; Treat function code as unsigned
; integer
BXHS lr ; If code is >= num then 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
BX lr ; Return
DoSub
SUB r0, r1, r2 ; Operation 1
BX lr ; Return
END ; Mark the end of this file
- ADRL
功能:在特定范围之内把地址加载到寄存器(并不会执行数据加载),如果在访问范围之内则汇编器会把该伪指令转换为两条数据处理汇编指令来加载地址,否则就报错。
语法格式入下:
ADRL{cond} Rd,label
同样label和ADR必须同属于一个代码段。
相比ADR,ADRL有更宽泛的访问范围,下面是lable相对当前指令距离限制
指令 | 偏移范围 |
---|---|
A32 的ADRL | 任何可以通过2个ADD/SUB指令生成的数据 |
T32 32位的ADRL | ±1MB |
T32 16位的ADRL | 不可用 |
- LDR
相对上面两条指令只能在当前代码段范围访问,LDR Rd,=Label伪指令可以跨段访问,至于为什么能跨段,因为汇编器+链接器做了更复杂的处理:)
参考文献
【1】DUI0801I_armasm_user_guide