最全【ARM汇编的堆栈问题】压栈运用 堆栈类型测试_满递减堆栈,2024年最新C C++性能优化面试题集锦

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事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指向栈顶

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值