本地变量的运行时内存分配如何在嵌入式系统中工作?

时间:2017-04-27 04:58:16

标签: c embedded rtos

我们正在使用ccrx编译器,embOS RTOS 代码中有一个函数,

void fun( ) 
{
    if(condition) 
    { int a;}
    else if(condition1)
   {int b;}............ 
    else
   { int z;}
} 

每当调用该函数时,相关的线程堆栈都会溢出。如果很少有int变量声明被注释,则线程堆栈不会溢出。

如何分配堆栈?条件成功后是否分配了内存?

1 个答案:

答案 0 :(得分:2)

让我们以GCC为例

void fun( int condition, int condition1 )
{
    if(condition)
    { int a; a=5;}
    else if(condition1)
   {int b; b=7;}
    else
   { int z; z=9; }
}

并选择一个目标,而不是为了获得ccrx而支付任何费用......

00000000 <fun>:
   0:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
   4:   e28db000    add r11, sp, #0
   8:   e24dd01c    sub sp, sp, #28
   c:   e50b0018    str r0, [r11, #-24] ; 0xffffffe8
  10:   e50b101c    str r1, [r11, #-28] ; 0xffffffe4
  14:   e51b3018    ldr r3, [r11, #-24] ; 0xffffffe8
  18:   e3530000    cmp r3, #0
  1c:   0a000002    beq 2c <fun+0x2c>
  20:   e3a03005    mov r3, #5
  24:   e50b3008    str r3, [r11, #-8]
  28:   ea000007    b   4c <fun+0x4c>
  2c:   e51b301c    ldr r3, [r11, #-28] ; 0xffffffe4
  30:   e3530000    cmp r3, #0
  34:   0a000002    beq 44 <fun+0x44>
  38:   e3a03007    mov r3, #7
  3c:   e50b300c    str r3, [r11, #-12]
  40:   ea000001    b   4c <fun+0x4c>
  44:   e3a03009    mov r3, #9
  48:   e50b3010    str r3, [r11, #-16]
  4c:   e1a00000    nop         ; (mov r0, r0)
  50:   e28bd000    add sp, r11, #0
  54:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
  58:   e12fff1e    bx  lr

没有分配

void fun( int condition, int condition1 )
{
    if(condition)
    { int a;/* a=5;*/}
    else if(condition1)
   {int b;/* b=7;*/}
    else
   { int z; /*z=9;*/ }
}

即使没有优化,这些变量也是死代码并且已经过优化

00000000 <fun>:
   0:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
   4:   e28db000    add r11, sp, #0
   8:   e24dd00c    sub sp, sp, #12
   c:   e50b0008    str r0, [r11, #-8]
  10:   e50b100c    str r1, [r11, #-12]
  14:   e1a00000    nop         ; (mov r0, r0)
  18:   e28bd000    add sp, r11, #0
  1c:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
  20:   e12fff1e    bx  lr

堆栈上有一些字节用于对齐,它们可能已经削减了一些并保持对齐但这是另一个主题。

这里的要点是因为在高级语言中你的变量只用在函数的一部分中并不意味着编译器必须这样做,编译器肯定是gcc,倾向于完成所有的堆栈分配在函数的开头和最后的清理。就像在这里做的那样......

这与

不同
int fun( void )
{
    static int x;
    x++;
    if(x>10) return(1);
    if(fun()) return(1);
    return(0);
}

给出了

00000000 <fun>:
   0:   e59f2030    ldr r2, [pc, #48]   ; 38 <fun+0x38>
   4:   e5923000    ldr r3, [r2]
   8:   e2833001    add r3, r3, #1
   c:   e353000a    cmp r3, #10
  10:   e5823000    str r3, [r2]
  14:   da000001    ble 20 <fun+0x20>
  18:   e3a00001    mov r0, #1
  1c:   e12fff1e    bx  lr
  20:   e92d4010    push    {r4, lr}
  24:   ebfffffe    bl  0 <fun>
  28:   e2900000    adds    r0, r0, #0
  2c:   13a00001    movne   r0, #1
  30:   e8bd4010    pop {r4, lr}
  34:   e12fff1e    bx  lr
  38:   00000000    andeq   r0, r0, r0

Disassembly of section .bss:

00000000 <x.4089>:
   0:   00000000    andeq   r0, r0, r0

它是一个局部变量但通过静态进入全局池,不像其他局部变量那样在堆栈上分配(或优化为寄存器)。

虽然有趣的是,这是一个不立即在堆栈上分配的情况,虽然在这种情况下这是好的,但如果你不需要,不要用递归加载堆栈。很好的优化。

由于您在高级语言中所做的事情,没有理由认为堆栈指针会在整个函数中多次更改。我的猜测是,即使在内存上浪费,开发编译器也更容易一次性完成。另一方面,当你去的时候会花费更多的指令(​​空间和时间)。