网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
源代码:
.data
str:.asciz " %5d\n %5d\n %5d\n %5d\n"
a:.word 1
b:.word 2
c:.word 3
d:.word 4
.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,=str
bl printf
mov r0, #0
ldmfd sp!,{lr}
mov pc,lr
.end
运行结果:
如果这一部分代码还是看不明白的话,那就请小可爱自行看前面写的文章了哦。【ARM嵌入式基础】
我们发现第四个数据并不是我们想要的数据,这里为什么会出错呢?就是因为我们调用printf也好scanf也好只能用R0~R3中的数据,R4中的数据取不到的。
如何压入栈中,输出正确结果呢?
⭐️我们知道了为什么出错,下面就来看看怎么不出错
从上面例子中来看,想输出内存中“d”的值,就要把获取到“d”数据的寄存器压到栈中,让调用printf的时候能找到它。我们看,r4其实已经通过取地址和间接寻址获取到了“d”的数据,那么只需要把r4压到栈中就可以。 |
压栈的指令在这篇文章中其实已经提到【ARM汇编模板】
//压栈
push {r4}
//出栈
pop {r4}
💖这里由于我们调用了printf,调用之后实际上已经把r4出栈,所以不用加pop {r4}
但是当没有运用函数让他出栈时要手动出栈,因为我们一定要遵循堆栈平衡原则,我们来看下一
压栈后的源代码:
.data
str:.asciz " %5d\n %5d\n %5d\n %5d\n"
a:.word 1
b:.word 2
c:.word 3
d:.word 4
.text
.globl main
main:
mov r4,#0
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]
push {r4}
ldr r0,=str
bl printf
mov r0, #0
ldmfd sp!,{lr}
mov pc,lr
.end
运行结果:
👍没错,就是这么简单!大家一定要动手试一下哦
ARM微处理器有哪几种堆栈工作方式呢?
既然提到了栈的运用,就把它给讲明白
堆栈是一种数据结构,按照先进后出的工作方式,使用一个称为堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈,而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈。同时,当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有4种类型的堆栈工作方式,ARM微处理器支持这四种类型的堆栈工作方式。
1. 满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生成。 2. 满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生成。 3. 空递增堆栈(EA):堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。 4. 空递增堆栈(ED):堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。 |
一共就这四种类型,下面我们可以验证一下ARM默认的是哪种堆栈类型
怎么来检测ARM堆栈的类型?
我们了解完堆栈的类型,发现有两个变量:满|空堆栈类型、递增|递减堆栈类型。
这样就得到了一个思路:
1. 通过测试栈顶的内容是不是空,来判断是满堆栈类型还是空堆栈类型 | 2. 通过测试栈顶的地址是增加还是减少,来判断是递增类型还是递减类型 |
直接上代码:
.data
fmt:.asciz "\n r4=%d sp=%d lr=%d\n"
.text
.globl main
main:
push {lr}
ldr r0,=fmt
mov r1,r4
mov r2,sp
mov r3,lr
bl printf
push {r4}
ldr r0,=fmt
ldr r1,[sp]
mov r2,sp
mov r3,lr
bl printf
mov r0, #0
ldmfd sp!,{lr}
mov pc, lr
.end
给大家分开讲解一下:
**①把r4中的内容给到r1,把栈顶的内容给到r2,把链接寄存器的内容给r3,然后调用printf输出
②这里的sp是R13寄存器(堆栈指针寄存器)的别名,sp指向栈顶
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!