B Label, BL Label
跳转到标号Label 处,B跳转指令的跳转范围大小为[0,32MB], 可以往前跳,也可以往后条,无条件跳转指令B主要用在循环,分之结构的汇编程序中,使用示例如下。
CMP R2, #0
REQ label 若R2 = 0,则跳转到label处。
label:
....
2 BL label
BL跳转指令表示带链接的跳转,在跳转之前,BL指令会先将当前指令的下一条指令地址(即返回地址)保存到LR寄存器中,然后跳转到label处执行,BL指令一半用在函数调用的场合,主函数在跳转到自函数执行之前,会先将返回地址,即当前跳转指令的吓一条指令地址保存到LR寄存器中,自函数执行结束后,LR寄存器中的地址将被赋值给PC,处理器就可以返回到原来的主函数中继续运行了。
3 BX Rm
BX 表示带状态切换的跳转,Rm寄存器中保存的是跳转地址,要跳转的目标地址处可能是ARM指令,也可能是Thumb指令,处理器根据Rm[0]位决定是切换到ARM状态还是切换到Thumb状态。
0 表示目标地址处是ARM指令,在跳转之前要先切换到Thumb状态。
1 表示目标地址处是Thumb指令,在跳转之前要先切换的跳转,使用方法和上面相同。不再赘述。
3.3 ARM寻址方式
ARM属于RISC体系结构,一个ARM汇编程序中的大部分汇编指令,基本上都和数据传输有关,在内存一寄存器,内存一内存,寄存器一寄存器之间来回传输数据。不通的ARM指令又有不同的寻址方式,比较常见的寻址方式有寄存器寻址,立即寻址,寄存器偏移寻址,寄存器间接寻址,基止寻址,多寄存器寻址,相对寻址等。
3.3.1 寄存器寻址
寄存器寻址比较简单,操作数保存在寄存器中,通过寄存器名就可以直接对寄存器中的数据进行读写。
MOV R1, R2 将寄存器R2中的值传递到R1
ADD R1, R2, R3; R1 = R2 + R3
3.3.2 立即数殉职
在立即数旬之中,ARM指令中的操作数为一个常数,立即书以#
为前缀,0x前缀表示该立即数为十六进制,不加前缀默认是十进制。
ADD R1, R1, #1 将R1寄存器中的值加1,并将结果保存到R1中。
MOV R1, #0xff 将十六进制常熟0xff 写到R1寄存器中
MOV R1, #12 将十进制常熟12放到R1寄存器中
ADD R1,R1,#16 R1 = R1 + 16
3.3.3 寄存器偏移寻址
寄存器偏移寻址可以看作寄存器寻址的一种特特例,通过第二个操作数operand2 的灵活配置,我们可以将第二个操作数做各种左移和右移操作,作为新的操作数使用。
MOV R2,R1,L5L, #3
ADD R3, R2, R1, L5L, #3
ADD R3, R2, R1, L5L, R0
常见的移位操作有逻辑移位和算数移位,两者的区别是,逻辑移位无论是左移还是右移,空缺的一律补0,而算数移位则不同,左移补0,右移补符号位。
3.3.4 寄存器间接寻址
寄存器间接寻址主要用来在内存和寄存器之间传递数据,寄存器中保存的是数据在内存中的存储地址,我们通过这个地址就可以在寄存器和内存之间传输数据,C预研中的指针操作,在汇编层次其实就是使用寄存器间接寻址实现的,寄存器间接寻址的使用示例以及说明如下所示。
LDR R1,[R2] 将R2中的值作为地址,取该内存地址上的数据,保存到R1
STR R1, [R2] 将R2中的值作为地址,将R1寄存器的值写入该内存地址。
3.3.5 基址寻址
基址殉职其实也属于寄存器间接寻址。两者的不同之处在于,基址寻址将寄存器中国呢的地址与一个偏移量相加,生成一个新地址,然后基于这个新地址去访问内存。
LDR R1, [FP,#2] 将FP中的值加2作为新的地址,取改地址上的值保存到R1
LDR R1, [FP, #2]
LDR R1,[Fp, R0] 取FP + R0位置的值存入R1
STR R1, [FP, #-2] 将R1存入FP - 2地址位置。
基址寻址一般用在查表,数据访问,函数的栈帧管理等场合,根据偏移的正负,基址寻址又可以分为向前索引寻址和向后索引殉职,如上面的第一条和第三条指令,就是向后缩阴寻址,而第6条指令则为向前索引寻址。
3.3.6 多寄存器寻址
STM/LDM 指令就属于多寄存器寻址,一次可以传输多个寄存器的值
LDMIA SP!, {R0-R2, R14} 将内存栈中的数据依次弹出到R14, R2,R1,R0
STMDB SP!, {R0-R2,R14} 将R0,R1,R2,R14依次压入栈
STMFD SP!,
在多寄存器寻址中,用大括号括起来的就是寄存器列表,寄存器之间用逗号隔开,如果是连续的寄存器,还可以使用连续符号连接,如R0R3,就表示R0,R1,R2这4个寄存器,。
LDM/STM指令一半和IA,IB,DA,DB组合使用,分别表示Increase After, Increase Before, Decrease After Decrease Before
ARM没有专门的入栈和出栈指令,ARM中的栈操作其实就是通过上面所讲的STM/LDM指令和栈指针SP配合操作完成的,栈一半可以分为以下四类
递增栈A 入栈时,SP栈指针从弟弟址往高地址方向增长。
递减栈D 入栈时,SP栈指针从高地址往低地址方向增长
满栈F,SP栈指针总是指向栈顶元素。
空栈E,SP栈指针总是指向栈顶元素。
空栈E,SP栈指针总是指向栈顶元素的下一个空闲的存储单元。
ARM默认使用满递减堆栈,通过STMFD/LDMFD指令配对使用,完成堆栈的入栈和出栈操作,ARM中的PUSH和POP指令其实就是LDM/STM的同义词。