关于栈和堆的一些资料。
首先是从理论上的东西。。网上转载来的,后面是看AVR代码时得出的一些东西。
硬件堆栈:或许也可以称作系统堆栈,是位于片内RAM区。有人说,只要能使用PUSH,POP指令的单片机,都可以说含有硬件堆栈。这样的说法我个人觉得不是很全面。通过指令进行压栈和出栈操作只是系统堆栈中的一种操做。系统堆栈还可以被隐含调用。例如,当调用子程序时,系统会主动把返回地址压入堆栈,并不需要用户通过指令操作。通常,栈底设在内存的高端,也就是把内存的最高一段空间划作栈区。这些都是向下生长栈。栈指针可能是专用的寄存器,也可能借用一通用寄存器。也有单片机是在数据区里划一块作栈区,可能是向上生长,也可能是向下生长。
硬件堆栈:是通过寄存器SPH,SPL做为索引指针的地址,是调用了CALL,RCALL等函数调用指令后硬件自动填充的堆栈!
软件堆栈:是编译器为了处理一些参数传递而做的堆栈,会由编译器自动产生和处理,可以通过相应的编译选项对其进行编辑。
简单一点说,硬件堆栈主要做为地址堆栈用,而软件堆栈主要会被分配成数据堆栈!
---摘自《AVR单片机C语言开发入门指导》-
如果没有硬堆栈,你可以选定一个寄存器作堆栈指针,通过软件实现堆栈操作。移植μC/OS-II也不一定要硬堆栈。ARM就很难说它的堆栈是软的还是硬的。32位的ARM指令中没有PUSH、POP指令。ARM习惯上用R13作堆栈指针(SP),但用别的寄存器作堆栈指针也未常不可。ARM习惯上用LDM/STM(多寄存器加载/存储指令)来操作堆栈,压多少,按什么顺序都能选择。应该说ARM是软硬结合的堆栈。
C代码(AVR-GCC编译,优化等级-00):
#include <avr/io.h>
int add(int a,int b)
{
}
int main(void)
{
c=add(a,b);
//c=sub(a,b);
}
汇编代码:
(省略一些boot代码)
。。。。。。。
00000054 <__ctors_end>:
。。。
0000008e <add>:
#include <avr/io.h>
int add(int a,int b)
{
000000d0 <main>:
}
int main(void)
{
c=add(a,b);
//c=sub(a,b);
}
00000104 <_exit>:
r28和r29一起组成SP指针,Y指针可以作为间接寻址,很明显的刚开始的时候Y指针和SP都在045F这里,后来在高处开了6个字节的空间来存放临时变量,所以Y指针成了这个软件堆栈的栈顶,在这个过程中都是使用Y和SP的配合来实现变量和数据的改变,以及恢复,硬件堆栈和软件堆栈在这里已经不怎么区分了。。。不清楚流程可以画个图来加深理解,好了,看了那么久,总算有点感觉了。。
栈是可变的,要留足够的空间才行,如果没有操作系统用的会很少,主要取决于函数的嵌套深度参数类型。
一般情况RAM存放三种类型的数据:
1.全局变量
2.堆(典型的MALLOC函数调用),这个得看你用了还是没有
3.栈,这个必然要用到的,有操作系统的话用的就更多了,每一个任务都会有一个栈,根据任务的函数嵌套程度可分配不同的大小。
具体要看什么编译器了,所以首先要估计一下你的栈要用多少,然后,再计算一下你的全局变量有多少,最后定一下可能的动态分配内存(堆)有多少就可以了。