• 2023/9/28 -- ARM


    【内存读写指令】

    1. int *p=0X12345678
    2. *p=100;//向内存中写入数据
    3. int a= *p;//从内存读取

    1.单寄存器内存读写指令

    1.1 指令码以及功能

    1. 向内存中写:
    2. str:向内存中写一个字(4字节)的数据
    3. strh:向内存写半个字(2字节)的数据
    4. strb:向内存写一个字节的数据
    5. 从内存读:
    6. ldr:从内存读取一个字的数据
    7. ldrh:从内存读取半个字的数据
    8. ldrb:从内存读取一个字节的数据

    1.2 格式

    1. 指令码{条件码} 目标寄存器 [目标地址]
    2. str 目标寄存器 ,[目标地址]:将目标寄存器的数据写入到以目标地址为起始的内存中
    3. ldr 目标寄存器 ,[目标地址]:从以目标地址为起始的内存中读一个字的数据到目标寄存器

    1.3 示例

    1. mov r1,#0XFFFFFFFF
    2. ldr r2,=0X40000000
    3. @向内存写入
    4. str r1,[r2]
    5. @从内存读
    6. ldr r3,[r2]

    1.4 单寄存器读写的地址索引方式

    1. 1.前索引
    2. mov r1,#0XFFFFFFFF
    3. ldr r2,=0X40000000
    4. str r1,[r2,#8]@将r1寄存器的值保存到r2+8为起始地址的内存中
    5. ldr r3,[r2,#8]@从r2+8为起始地址的内存中读
    6. 2.后索引
    7. mov r1,#0XFFFFFFFF
    8. ldr r2,=0X40000000
    9. str r1,[r2],#8 @将r1寄存器的值保存到r2为起始地址的内存中,r2=让r2+8
    10. 3.自动索引
    11. mov r1,#0XFFFFFFFF
    12. ldr r2,=0X40000000
    13. str r1,[r2,#8]! @将r1寄存器的值保存到r2+8为起始地址的内存中,r2=r2+8

    2.批量寄存器的内存读写方式

    2.1 指令码以及格式

    1. 向内存写:
    2. stm 目标地址,{寄存器列表}
    3. 将寄存器列表中每一个寄存器的值都写道目标地址指向的连续空间之中
    4. 从内存读
    5. ldm 目标地址,{寄存器列表}
    6. 将目标地址指向的连续内存中的数据读到寄存器列表中的寄存器中
    7. 注意事项:
    8. 1.如果寄存器列表中寄存器的编号连续,可以用-表示列表,如果不连续,用,分割寄存器
    9. {r1-r5,r7}
    10. 2.无论寄存器列表中如何表示,我们在读写内存的时候始终是低地址 对应低寄存器编号

    2.2 示例代码

    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000000
    7. stm r6,{r1,r2,r3,r4,r5} @将r1-r6寄存器的值写道r6指向的连续内存中
    8. ldm r6,{r7,r8,r9,r10,r11}@从r6指向的连续内存中读取数据保存到r7-r11寄存器中

    2.3 批量寄存器的地址增长方式

    每次向指定寄存器保存的地址中写入一个数据,保存地址的寄存器保存的地址也会发生相应的改变

    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000000
    7. stm r6!,{r1-r5}
    8. 先向r6指向的内存中写一个数据,然后r6保存的地址向地址大的方向增长
    ia后缀
    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000000
    7. stmia r6!,{r1-r5}
    8. 先向r6指向的内存中写一个数据,然后r6保存的地址向地址大的方向增长
    ib后缀
    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000000
    7. stmib r6!,{r1-r5}
    8. 先让R6寄存器保存的地址往地址大的方向增长,再向R6寄存器保存的地址中写入数据
    da后缀
    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000800
    7. stmda r6!,{r1-r5}
    8. 先向R6指向的内存中存数据,然后R6寄存器保存的地址往地址小的方向增长
    dB后缀
    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000800
    7. stmdb r6!,{r1-r5}
    8. 先将R6寄存器保存的地址往地址小的方向增长,再往R6寄存器保存的地址内存中存入数据

    1. mov r1,#1
    2. mov r2,#2
    3. mov r3,#3
    4. mov r4,#4
    5. mov r5,#5
    6. ldr r6,=0X40000000
    7. stmia r6!,{r1-r5} @ia存,db取
    8. ldmdb r6!,{r7-r11}

    3.栈内存读写

    栈指针寄存器:R13/SP

    栈:栈本质上就是一段内存,我们在内存中指定一片区域用于保存一些临时数据,这片区域就是栈区

    3.1 栈的类型

    1. 增栈:压栈结束后,栈顶往地址大的方向增长
    2. 减栈:压栈结束后,栈顶往地址小的方向增长
    3. 空栈:压栈结束后,栈顶区域没有有效数据
    4. 满栈:压栈结束后,栈顶区域存放有效数据
    5. 空增栈(EA)/空减栈(ED)/满增栈(FA)/满减栈(FD)
    6. ARM使用的栈是满减栈

    3.2 满减栈压栈出栈操作

    1. ex1
    2. ldr sp,=0X40000020 @指定顶地址
    3. mov r1,#1
    4. mov r2,#2
    5. mov r3,#3
    6. mov r4,#4
    7. mov r5,#5
    8. push {r1-r5} @压栈
    9. pop {r6-r10} @将栈顶元素数值出栈
    10. ex2:
    11. ldr sp,=0X40000020 @指定顶地址
    12. mov r1,#1
    13. mov r2,#2
    14. mov r3,#3
    15. mov r4,#4
    16. mov r5,#5
    17. STMDB sp!,{r1-r5} @压栈
    18. LDMIA sp!,{r6-r10} @将栈顶元素数值出栈
    19. EX3:
    20. ldr sp,=0X40000020 @指定顶地址
    21. mov r1,#1
    22. mov r2,#2
    23. mov r3,#3
    24. mov r4,#4
    25. mov r5,#5
    26. STMfd sp!,{r1-r5} @压栈
    27. LDMfd sp!,{r6-r10} @出栈

    4.栈实例---叶子函数的调用过程

    1. .text
    2. .global _start
    3. _start:
    4. ldr sp,=0X40000020 @初始化栈
    5. b main
    6. main:
    7. mov r1,#1
    8. mov r2,#2
    9. bl func
    10. add r3,r1,r2
    11. b main
    12. func:
    13. @压栈保护现场
    14. stmfd sp!,{r1,r2}
    15. mov r1,#3
    16. mov r2,#4
    17. sub r4,r2,r1
    18. @出栈恢复现场
    19. ldmfd sp!,{r1,r2}
    20. mov pc,lr @返回main函数
    21. wh:
    22. b wh
    23. .end

    5.栈实例---非叶子函数的调用过程

    1. .text
    2. .global _start
    3. _start:
    4. ldr sp,=0X40000020 @初始化栈
    5. b main
    6. main:
    7. mov r1,#1
    8. mov r2,#2
    9. bl func
    10. add r3,r1,r2
    11. b main
    12. func:
    13. @压栈保护现场
    14. stmfd sp!,{r1,r2,lr}
    15. mov r1,#3
    16. mov r2,#4
    17. bl fun1
    18. sub r4,r2,r1
    19. @出栈恢复现场
    20. ldmfd sp!,{r1,r2,lr}
    21. mov pc,lr @返回main函数
    22. fun1:
    23. @压栈保护现场
    24. stmfd sp!,{r1,r2}
    25. mov r1,#4
    26. mov r2,#5
    27. mul r5,r1,r2
    28. @出栈恢复现场
    29. ldmfd sp!,{r1,r2}
    30. mov pc,lr
    31. wh:
    32. b wh
    33. .end

  • 相关阅读:
    面试了20+前端大厂,整理出的面试题
    docker自定义镜像
    lego_loam 代码阅读与总结
    本地Image Registry Harbor安装
    23种设计模式之模板模式
    pinctrl子系统 - 源码解析(五)
    基于Spring Boot的大学校园防疫与服务系统毕业设计源码111556
    SpringBoot整合Groovy脚本,实现动态编程
    Spring(存储Bean对象五大类注解,获取Bean对象三种注入方式)
    深入解读 EVM 的生态帝国
  • 原文地址:https://blog.csdn.net/weixin_54147737/article/details/133651862