提到压栈,看过上一篇文章的小伙伴肯定都很熟悉,用push就可以。 这里给大家介绍另外一个压栈的指令`LDM R13!`,细心的铁子肯定会发现,这不就是第一天给大家ARM汇编模板`main框架`中的语句吗? 没错是的,之前说过R13的别名可以叫`sp`(堆栈指针,并且指在最上面元素),STM刚刚讲到是用来传送数据的存储指令,如果把寄存器中的内容存储到R13(堆栈指针),那不就代表把内容放到堆栈中了嘛! 举个例子 用输出超过三个数的例子来试一下(因为超出三个数必须要压栈) 源代码: .data
str:.asciz " %5d\n %5d\n %5d\n %5d\n %5d\n %5d\n"
a:.word 1
b:.word 2
c:.word 3
d:.word 4
e:.word 5
f:.word 6
.text
.globl main
main:
stmfd sp!,{lr}
ldr r0,=a
ldr r1,[r0]
ldr r0,=b
ldr r2,[r0]
ldr r0,=c
ldr r3,[r0]
ldr r0,=d
ldr r4,[r0]
ldr r0,=e
ldr r5,[r0]
ldr r0,=f
ldr r6,[r0]
stmfd r13!,{r4,r5,r6}
ldr r0,=str
bl printf
mov r0,
ldmfd sp!,{lr}
mov pc,lr
.end
这里我先把6个数从内存中读了出来,然后用stmfd r13!,{r4,r5,r6} 进行了压栈操作(批量存储,寄存器之间用“,”隔开即可)
运行结果: 这样,我们就学会了除push的另外一个压栈方式stmfd R13 ,我这里用的是ARM默认的满递减堆栈(FD)的压栈方式,不同的堆栈类型可以用图片中不同的类型指令。
二、如何让寄存器一次性取到多个存储器中的地址? 上面的例子可以看到我们用LDR一次只能取一个地址,写的非常的麻烦 那今天学了LDM就能让你方便很多,先上原理,再上例子 多寄存器寻址
多寄存器寻址是指一次可以传送多个寄存器的值,允许一条指令可以传送16个寄存器的任何子集。多寄存器寻址对应后缀的含义如下: |
- I:Increment 地址递增
- D:Decrement 地址递减
- A:After 传递后地址才开始变化
- B:Before 地址先变化后才开始传送
例如: LDMIA R0,{R1,R2,R3,R4}
这其实是执行了四次
R1←[R0]
R2←[R0+4]
R3←[R0+8]
R4←[R0+12]
因为IA后缀表示每次执行完加载/存储后,R0按字长度增加。因此,指令可将连续存储单元的值传送到R1~R4
运用LDM简化后的代码(还是用上面的例子) 源代码: .data
str:.asciz " %5d\n %5d\n %5d\n %5d\n %5d\n %5d\n"
a:.word 7
b:.word 6
c:.word 5
d:.word 4
e:.word 3
f:.word 2
.text
.globl main
main:
stmfd sp!,{lr}
ldr r2,=a
ldmia r2,{r4-r9}
mov r1,r4
mov r2,r5
mov r3,r6
push {r7,r8,r9}
ldr r0,=str
bl printf
mov r0,
ldmfd sp!,{lr}
mov pc,lr
.end
用多寄存器寻址指令ldmia r2,{r4-r9} 把{r4,r5,r6,r7,r8,r9}寄存器以此存上a,b,c,d,e,f 的地址。我们这里用的是IA每次传输后地址加1,根据需求也可以用上面图片中其他类型的后缀。
运行结果: 学会了多寄存器寻址就大大降低了代码行数
再次简化后的代码(两个用法融合)
运用LDM取址简化了取址的操作——当数量超过3个数据后——必须用到堆栈——又学到了新的压栈方法——那么我们可以把上面的两个用法融合到一起。 源代码: .data
str:.asciz " %6d\n %6d\n %6d\n %6d\n %6d\n %6d\n"
a:.word 666666
b:.word 66666
c:.word 6666
d:.word 666
e:.word 66
f:.word 6
.text
.globl main
main:
stmfd sp!,{lr}
ldr r0,=a
ldmia r0,{r1,r2,r3,r4,r5,r6}
stmfd R13!,{r4,r5,r6}
ldr r0,=str
bl printf
mov r0,
ldmfd sp!,{lr}
mov pc,lr
.end
运行结果:
由于printf是从R1开始输出,所以把前面的R4直接改成R1,就不用在进行MOV了。
对比看一下两个代码:
小提示:
多个连续的寄存器可以用“ - ” 符号链接;不连接的寄存器用“,” 分隔书写,如:
LDMIA R0,{R1-R6}
LDMIA R0,{R1,R3-R7,R9}
总结: 今天讲到了两个很重要的指令LDM、STM(批量加载,批量存储)
1.可运用STM和LDM加上后缀进行压栈和出栈,例如:STMFD R13! 和LDMFD R13! 。
2.运用LDM可进行多寄存器寻址,例如:LDMIA 不同的寻址需求加上不同的类型后缀。
3.指令LDM和STM只能从一片连续的存储器中读取数据,不连续还是需要单独读取。
学会了吗?学会了送自己一朵小花花呀!
还没有关注汤姆的朋友,点个关注每天学一点汇编
下期预告:暂定(*^▽^*)
|
|
评论(0)