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

How does runtime memory allocation for local variable's work in embedded systems?

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

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

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

栈是怎么分配的?条件成功后不会分配内存吗?

让我们以 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

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

虽然有趣的是,这是一个没有立即在堆栈上分配的情况,尽管在这种情况下这很好,但如果不需要,不要让递归给堆栈增加负担。不错的优化。

没有理由假设堆栈指针会因为您在高级语言中所做的而在整个函数中多次更改。我的猜测是它使编译器的开发更容易,可以预先一次性完成所有工作,即使这会浪费内存。另一方面,当你去的时候会花费更多的指令(​​space 和时间)。