[008] [ARM-Cortex-M3/4] 局部变量一定是保存在栈区的吗

ARM
Contents
初步分析
验证猜想
总结

IDE:Keil MDK V5.33
内核:Cortex-M3

引言

局部变量(局部静态变量除外)一般是保存在栈区的,但这不是绝对的,有时编译器会对其进行优化,不为其开辟栈空间。

1 初步分析

不加volatile关键字修饰局部变量的C函数与反汇编代码如下:

  • C代码
int mymain()
{
	int a = 0x53, b = 3;
	return a / b;
}
  • 汇编代码
MOVS     r2,#0x53		; r2 = 0x53
MOVS     r1,#3			; r1 = 3
SDIV     r0,r2,r1		; r0 = r2 / r1 = 0x53 / 3(SDIV为带符号除法,需硬件支持)

所有计算过程均在CPU内部,没有出现访问内存的操作,当然也没开辟栈空间。

volatile关键字后的汇编代码如下:

PUSH     {r2,r3,lr}
MOVS     r0,#0x53
STR      r0,[sp,#4]
MOVS     r0,#3
STR      r0,[sp,#0]
LDRD     r1,r0,[sp,#0]
SDIV     r0,r0,r1
POP      {r2,r3,pc}
  • 用栈来存储局部变量,先让寄存器r2,r3,lr入栈:
    在这里插入图片描述
  • ARM芯片均为向下增长的满栈
  • 标号小的寄存器后入栈(先出栈),lr即r14
  • r0 = 0x53,保存至sp+4所示地址,即*(sp+4) = r0 = 0x53
  • r0 = 3,保存至sp所示地址,即*sp = r0= 3
  • 执行LDRD r1,r0,[sp,#0]指令,从sp位置取出双字数据(2个4字节),r1加载低32位数据,r0加载高32位数据,即r1 = *sp = 3,r0 = *(sp+4) = 0x53
  • r0 = r0 / r1 = 0x53 / 3
  • 最后弹栈释放栈区内存,并将pc = lr,实现程序跳转

编译器对局部变量的优化是将其值直接加载到cpu内部寄存器的,那么是不是只要当这些寄存器空闲就满足优化条件呢?

2 验证猜想

定义一个具有13个局部变量的函数:

int mymain()
{
	int c0 = 7, c1 = 7, c2 = 7, c3 = 7, c4 = 7, c5 = 7, c6 = 7, c7 = 7;
	int c8 = 7, c9 = 7, c10 = 7, c11 = 7, c12 = 7;
	
	return 0;
}

查看其反汇编代码:
在这里插入图片描述
这些局部变量并没存放到栈中,而是用r0~r12、lr来保存它们的值。

将变量个数再+1后的反汇编代码:
在这里插入图片描述
为新增的变量开辟了栈空间。

3 总结

  • 局部变量不加volatile时,如果当前有空闲的寄存器(sppc除外),编译器会对其进行优化,即直接将值加载到这些寄存器中,在cpu内部完成运算,不需要访问内存和开辟栈空间;
  • 局部变量加volatile时,编译器不会对其进行优化,且永远都是先在栈中保存局部变量的值,再从栈中读出这些数据进行相应运算,最后弹栈释放开辟的栈内存。

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯西的彷徨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值