局部变量的运行时内存分配在嵌入式系统中如何工作?
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 和时间)。
我们使用的是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 和时间)。