目录
一、多寄存器内存访问指令
二、多寄存器内存访问指令的寻址方式
三、栈的种类与使用
3.1栈的概念
3.2栈的分类
四、栈的应用举例
4.1叶子函数的调用过程举例
4.2非叶子函数的调用过程举例
一、多寄存器内存访问指令
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STM R11,{R1-R4}
@ 将R1-R4寄存器中的数据写入到以R11为起始地址的内存空间中
@ LDM R11,{R6-R9}
@ 将以R11为起始地址的内存空间中的数据读取到R6-R9寄存器中
@ 当寄存器编号不连续时,使用逗号分隔
@ STM R11,{R1,R2,R4}
@ 不管寄存器列表中的顺序如何,存取时永远是低地址对应小编号的寄存器
@ STM R11,{R3,R1,R4,R2}
@ 自动索引照样适用于多寄存器内存访问指令
@ STM R11!,{R1-R4}
二、多寄存器内存访问指令的寻址方式
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STMIA R11!,{R1-R4}
@ 先存储数据,后增长地址
@ STMIB R11!,{R1-R4}
@ 先增长地址,后存储数据
@ STMDA R11!,{R1-R4}
@ 先存储数据,后递减地址
@ STMDB R11!,{R1-R4}
@ 先递减地址,后存储数据
三、栈的种类与使用
3.1栈的概念
栈的本质就是一段内存,程序运行时用于保存一些临时数据
如局部变量、函数的参数、返回值、以及程序跳转时需要保护的寄存器等
3.2栈的分类
增栈:压栈时栈指针越来越大,出栈时栈指针越来越小
减栈:压栈时栈指针越来越大,出栈时栈指针越来越小
满栈:栈指针指向最后一次压入到栈中的数据,压栈时需要先移动栈指针到相邻位置然后再压栈
空栈:栈指针指向最后一次压入到栈中的数据的相邻位置,压栈时可直接压栈,之后需要将栈指针移动到相邻位置
栈分为空增(EA)、空减(ED)、满增(FA)、满减(FD)四种ARM处理器一般使用满减栈
由于是满减栈使用STMDB进行压栈使用LDMIA进行出栈
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STMFD R11!,{R1-R4}
@ LDMFD R11!,{R6-R9}
因为是FD可以直接用FD省的算怎么入怎么出,编译器会自动替换
四、栈的应用举例
4.1叶子函数的调用过程举例
得到了一个不应该的结果,由于主函数和子函数使用相同的寄存器,但用的值不同,在不增加寄存器的前提下让结果正确,就用到了栈。
@ 初始化栈指针
@ MOV SP, #0x40000020
@ MIAN:
@ MOV R1, #3
@ MOV R2, #5
@ BL FUNC
@ ADD R3, R1, R2
@ B STOP
@ FUNC:
@ 压栈保护现场
@ STMFD SP!, {R1,R2}
@ MOV R1, #10
@ MOV R2, #20
@ SUB R3, R2, R1
@ 出栈恢复现场
@ LDMFD SP!, {R1,R2}
@ MOV PC, LR
4.2非叶子函数的调用过程举例
@ MOV SP, #0x40000020
@ MIAN:
@ MOV R1, #3
@ MOV R2, #5
@ BL FUNC1
@ ADD R3, R1, R2
@ B STOP
@ FUNC1:
@ STMFD SP!, {R1,R2,LR}
@ MOV R1, #10
@ MOV R2, #20
@ BL FUNC2
@ SUB R3, R2, R1
@ LDMFD SP!, {R1,R2,LR}
@ MOV PC, LR
@ FUNC2:
@ STMFD SP!, {R1,R2}
@ MOV R1, #7
@ MOV R2, #8
@ MUL R3, R1, R2
@ LDMFD SP!, {R1,R2}
@ MOV PC, LR
@ 执行叶子函数时不需要对LR压栈保护,执行非叶子函数时需要对LR压栈保护
局部变量是栈中的,栈中数据不会自动清除所以,当分配一个新变量时,栈指针指到哪里变量的初始值就是该地址未清除时留下的值,而全局变量在BSS中,操作系统的初始化时会将这里自动清零,所以全局变量的初值是0.