You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ARM Cortex中栈指针递增分配局部变量空间的技术疑问

ARM Cortex中栈指针递增分配局部变量空间的技术疑问

首先看你贴的代码和反汇编内容:

C代码

void user_main(void)
{
    u32 asd;

    osGetSysCnt(&asd);
}

反汇编代码

void user_main(void)
{
10040230:   b507        push    {r0, r1, r2, lr}
    u32 asd;

    osGetSysCnt(&asd);
10040232:   a801        add r0, sp, #4
10040234:   f000 f801   bl  1004023a <osGetSysCnt>
}
10040238:   bd07        pop {r0, r1, r2, pc}

你的疑问是:为什么栈指针要递增?这不会覆盖已经压栈的寄存器吗?


嘿,这个问题其实是个小误解,咱们慢慢拆解:

首先要明确:这里并没有递增栈指针sp本身!你看到的add r0, sp, #4只是把sp + 4的结果赋值给了r0(用来给osGetSysCnt传参数,也就是局部变量asd的地址),sp的值从头到尾都没变化哦。

接下来咱们捋清楚栈的布局和操作逻辑:

  1. 函数开头的push {r0, r1, r2, lr}是把这4个寄存器压入栈中——ARM Cortex的栈默认是向下生长的,所以执行这条指令后,sp会向下移动16字节(每个32位寄存器占4字节),把这四个寄存器的值依次存在栈里。
  2. 编译器之所以选择sp + 4作为asd的地址,是因为它复用了栈上已经被压栈的寄存器空间:这个地址对应的是之前压栈的r1的存储位置。
  3. 为什么可以这么做?因为在这个user_main函数里,我们根本不需要用到r1原来的数值(而且r1属于ARM的「调用者保存寄存器」,调用这个函数的代码本来就该自己负责保存r1的值),所以编译器直接把这个闲置的栈空间拿来存局部变量asd,省得再额外调整sp来分配新的栈空间,算是个小优化。
  4. 最后执行pop {r0, r1, r2, pc}时,asd的值会被弹回r1,但因为调用者不依赖r1的原有值,所以完全不会有问题。

简单说就是:你误以为sp被修改了,但其实只是用sp计算了一个地址;而且这个地址复用了闲置的寄存器栈空间,不会造成什么不良影响~

备注:内容来源于stack exchange,提问作者Korsarq

火山引擎 最新活动