ARM 常用指令

b & bl & bx & blx

bl 在转移到子程序执行前,将下一条指令的地址放到lr中。
b 不设置lr。
bx 不设置lr,跳转到的地址处指令既可以是ARM 指令,也可以是Thumb指令,可能会伴随处理器状态的切换。
blx 设置lr,可以有处理器状态的切换。

 B label   @ 相对跳转,范围为+-32M
 BL label  @ 相对跳转,会先设置lr
 BX Rm     @ 绝对跳转,因为寄存器中可放任意地址,
           @ 如在函数最后 bx lr 用来返回,可以有模式切换
           @ 当Rm的状态位(第0位)为1时,表示将引入thumb状态
           @ 当Rm的状态位(第0位)为0时,表示将引入arm状态

 BLX label @ 相对跳转,会先设置lr,可以有ARM、THUMB模式切换
 BLX Rm    @ 绝对跳转,会先设置lr,可以有ARM、THUMB模式切换

mov & mvn

mov

格式 :

MOV{S}{cond} Rd, Operand2
MOV{cond} Rd, #imm16

#imm16 范围0~65535,前面别忘了加#
Operand2 就更为灵活了,可以是一个带移位的寄存器值,或是一个常数值,这个常数值不同于#imm16。

带移位的寄存器:

Rm {, shift}
shift : ASR #n, LSL #n, LSR #n...

常数值以8位来表示值,其余位用来表示移位等信息:

In ARM instructions, constant can have any value that can be produced by rotating an 8-bit value right by any even number of bits within a 32-bit word.
In Thumb instructions, constant can be:
• any constant that can be produced by shifting an 8-bit value left by any number of bits within a 32-bit word
• any constant of the form 0x00XY00XY
• any constant of the form 0xXY00XY00
• any constant of the form 0xXYXYXYXY.

mvn

 mvn Rd,Rm

将寄存器Rm按位取反后传送到目标寄存器(Rd)中。

str & ldr

str

 str r1, [r2]     @ 将寄存器r1的值写入主存[r2]中
 str r1, [r2, #4] @ 主存地址为r2+4
 str r1, [r2], #4 @ 主存地址为r2+4,同时,r2=r2+4

ldr

LDR (immediate offset,立即数偏移)

; 将主存中 Rn+offset 地址处的值装入Rt中
; Rt = Mem[Rn+offset] 意指将主存中Rn+offset地址处数据加载到Rt寄存器中,下不赘述
LDR{type}{cond} Rt, [Rn {, #offset}] 

Rt : 目标寄存器,从内存中取数据放入该寄存器中。
Rn : 该寄存器内放有地址,与offset偏移量组合为主存中的一个地址。地址为Rn+offset。
offset : 偏移量可以为空,根据处于ARM或THUMB模式和{type}的不同选择,offset可以取值的范围也不同,如果懒得查文档,在ARM模式下-255~255的取值范围是不会有错的。
{type} : 在32位的处理器中,Rt的长度为32位,即目标寄存器的长度不可改变,但可以通过{type}的设置指定从主存中取到的数据的长度:

  • B -> 从主存某处取一个字节,采用零扩展的方法将其放到Rt中;
  • SB -> 取一个字节,采用符号扩展;
  • H -> 取两个字节,采用零扩展;
  • SH -> 取两个字节,采用符号扩展;
  • 为空时默认为取四个字节,此时与目标寄存器一样长度,不需要考虑扩展问题。

{cond}为条件码,即根据cpsr中的条件码的状态选择是否执行该指令。

以上5条在伺候如果出现且含义相同时,不再赘述。

; Pre-indexed addressing(带前索引寻址)
; Rt = [Rn+offset], Rn = Rn + offset, 类似于前置++
LDR{type}{cond} Rt, [Rn, #offset]!
; Post-indexed addressing (带后索引寻址)
; Rt = [Rn], Rn = Rn + offset, 类似于后置++
LDR{type}{cond} Rt, [Rn], #offset
; 同时加载数据到两个寄存器
; Rt = [Rn+offset], Rt2 = [Rn+offset+4]
LDRD{cond} Rt, Rt2, [Rn {, #offset}]
; pre-indexed, doubleword
LDRD{cond} Rt, Rt2, [Rn, #offset]! 
; post-indexed, doubleword
LDRD{cond} Rt, Rt2, [Rn], #offset 

注意:


  • 在前索引和后索引的形式中,Rn和Rt不能是同一个寄存器。
  • Rn和Rt2不能是同一个寄存器。(双字指令)
  • thumb模式双字指令中,Rt和Rt2不能是sp和pc寄存器。
  • ARM模式双字指令中,Rt只能是偶数的寄存器,Rt2必须是R(t+1),即Rt后的那个寄存器,Rt不能是lr,Rt最好不要使用R12。
  • {type}为空的ldr指令,可以使用sp和pc。详细情况见下面引用

In ARM instructions you can use PC for Rt in LDR word instructions and PC for Rn in LDR instructions.
Other uses of PC are not permitted in these ARM instructions.
In Thumb instructions you can use PC for Rt in LDR word instructions and PC for Rn in LDR instructions. Other uses of PC in these Thumb instructions are not permitted.
You can use SP for Rn.
In ARM, you can use SP for Rt in word instructions. You can use SP for Rt in non-word instructions in ARM code but this is deprecated in ARMv6T2 and above.
In Thumb, you can use SP for Rt in word instructions only. All other use of SP for Rt in these instructions are not permitted in Thumb code.

LDR (PC-relative)

; Rt = Mem[label]
LDR{type}{cond}{.W} Rt, label

LDRD{cond} Rt, Rt2, label ; Doubleword

例如

Reset:
    ldr r0, Reset

汇编为

00000020 <Reset>:
  20:   e51f0008    ldr r0, [pc, #-8]   ; 20 <Reset>

如果当前指令在执行,那么下一条指令一定正在译码,再下一条指令正在读取,PC值实际上是正在读取的指令的地址,即pc的值为0x20+4*2,所以r0中的值是主存中0x20处的值:0xe51f0008。当然此处只是为了演示,取一条指令的值没啥实际意义。

ARM LDR, LDRB, LDRSB, LDRH, LDRSH 时,offset的范围是+/-4095。

LDR (register offset)

Rt = Mem[Rn +/- (Rm <</>> #n)]
LDR{type}{cond} Rt, [Rn, +/-Rm {, shift}] ; register offset
LDR{type}{cond} Rt, [Rn, +/-Rm {, shift}]! ; pre-indexed ; ARM only
LDR{type}{cond} Rt, [Rn], +/-Rm {, shift} ; post-indexed ; ARM only
LDRD{cond} Rt, Rt2, [Rn, +/-Rm] ; register offset, doubleword ; ARM only
LDRD{cond} Rt, Rt2, [Rn, +/-Rm]! ; pre-indexed, doubleword ; ARM only
LDRD{cond} Rt, Rt2, [Rn], +/-Rm ; post-indexed, doubleword ; ARM only

shift : 对于ARM, word or byte指令,可以是 (LSL #0-31) (LSR #1-32) (ASR #1-32) (ROR #1-31) (RRX)

LDR pseudo-instruction

LDR{cond}{.W} Rt, =expr
LDR{cond}{.W} Rt, =label_expr

expr 是一个数值,可以用mov或mvn指令来实现,那么使用mov或mvn指令,否则会将该值保存到常量池中(就是把expr的值保存到内存中),然后使用ldr的相对pc偏移的形式加载该值到寄存器。
label_expr

label_expr is a PC-relative or external expression of an address in the form of a label plus or minus a numeric value.
使用ldr伪指令,就不用担心expr是否太大,也不用担心label_expr是否距离太远。

LDR r3,=0xff0 ; loads 0xff0 into R3
; => MOV.W r3,#0xff0
LDR r1,=0xfff ; loads 0xfff into R1
; => LDR r1,[pc,offset_to_litpool]
; ...
; litpool DCD 0xfff
LDR r2,=place ; loads the address of
; place into R2
; => LDR r2,[pc,offset_to_litpool]
; ...
; litpool DCD place

请看下面的例子:

@ boot.S文件,在0x0附近
    ldr pc, =main           @ 调用main函数

main函数的位置为0x30000000,调用者和被调用者的距离相差大于32M。
会被汇编为:

  7c:   e59ff020    ldr pc, [pc, #32]  ; a4
  ...
  a4:   30000000    @ main函数的地址储存在这

执行到该指令时,pc值为0x7c+8=0x84,0x84+32=0xa4。
所以即使要加载的值很大,也可以一条指令搞定,只需要在附近分配一块内存保存该数据。
在某些关键的地方,如异常向量表,你只能放一条跳转指令,如果跳转的范围超过32M,那么使用B系列的指令是行不通的,这时你可以放心的使用 ldr pc,=label 这条伪指令。它会翻译成一条指令,而不是多条指令。

 ldr r0, =0x1234  @ 加载立即数到寄存器
 ldr r0, =label   @ 将标签label对应的地址加载到寄存器
 ldr r1, [r2]     @ 将主存[r2]中的值加载到寄存器
 ldr r1, [r2, #4] @ 将主存[r2+4]中的值加载到寄存器
 ldr r1, [r2], #4 @ 同上,同时r2=r2+4

lsl & asl & lsr & asr & ror & rrx

一般,逻辑左移同算术左移,右边统一添0 。
逻辑右移,左边统一添0 。
算术右移,左边添加的数和符号位(最高位)相同,这说明把寄存器里的值当成是一个有符号数,计算机里一般用补码表示有符号数。
LSL 逻辑左移
ASL 算术左移
LSR 逻辑右移
ROR 循环右移
RRX 带扩展的循环右移

LSL{S}{cond} Rd, Rm, Rs
LSL{S}{cond} Rd, Rm, #sh

移动的位数有Rs或#sh给出,操作于Rm中的值上,产生的结果放在Rd中。

个人水平有限, 以上内容可能有疏漏的地方, 详情请参考 http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0184b/I62726.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值