2015-06-15 91 views
1

我有一个STM32F103VCT6微控制器,SRAM的48KB,而且最近我有一个内存冲突:如何将堆栈对齐到SRAM的末尾?

我有一些静态变量(可以称之为A)位于与0x7000大小堆和我写了一些简单的功能获取有关堆和栈信息:

void check(int depth) { 
    char c; 
    char *ptr = malloc(1); 
    printf("stack at %p, heap at %p\n", &c, ptr); 
    if (depth <= 0) return; 
    check(depth-1); 
} 

所以我有这样的事情:

stack at 2000939b, heap at 20008fd0 
stack at 20009383, heap at 20008fe0 
stack at 2000936b, heap at 20008ff0 
stack at 20009353, heap at 20009000 
stack at 2000933b, heap at 20009010 
stack at 20009323, heap at 20009020 
stack at 2000930b, heap at 20009030 
stack at 200092f3, heap at 20009040 
stack at 200092db, heap at 20009050 
stack at 200092c3, heap at 20009060 
stack at 200092ab, heap at 20009070 

所有静态变量(incliding A)已经得到了他们的堆,所以堆位于0x8fd0。而且看起来,原来,堆栈指针位于0x939b,那就是远离48KB(0xc000

当我改变了A可变大小0x4000我有这样的画面:

stack at 2000639b, heap at 20005fd0 
stack at 20006383, heap at 20005fe0 
stack at 2000636b, heap at 20005ff0 
stack at 20006353, heap at 20006000 
stack at 2000633b, heap at 20006010 
stack at 20006323, heap at 20006020 
stack at 2000630b, heap at 20006030 
stack at 200062f3, heap at 20006040 
stack at 200062db, heap at 20006050 
stack at 200062c3, heap at 20006060 
stack at 200062ab, heap at 20006070 

所以,似乎堆栈位置不是位于SRAM的末尾,而是一些如何依赖用户定义的变量。

如何将堆栈对齐到SRAM的最末端(48kb)?

我正在使用CooCox IDE和GNU Tools ARM Embedded toolchain。

谢谢!

编辑:

对不起,我有些误会这里,A不是const的,我已经把它称为静态唯一关键字的原因是:

static uint8_t A[A_SIZE];  
printf("A is at %p\n", &A); 

这表明A位于内存开始:

A is at 20000c08 
+1

为什么你认为静态变量分配在堆上?从您的结果看来,它们更有可能位于公羊顶部,并且堆叠从它们下面开始。试着打印'A'的地址。 – caf

+1

这可能是由您的链接脚本控制的。阅读它(并阅读mapfile以查看其结果) –

+0

“我有一些静态变量(让我们称之为A)位于堆中”这没有任何意义,所以也没有问题(为什么所有这些投票? )。静态变量和动态变量几乎是彼此的对立面,因此是“静态”和“动态”。静态变量分配在'.data/.bss'中,堆中的动态变量和堆栈中的局部变量。现在,你在谈论静态变量还是动态变量?因为它们不能同时存在。请显示“A”的变量声明和初始化。 – Lundin

回答

0

我发现原因:这是因为堆栈大小实际上是固定的,它位于堆(如果我可以称它为堆)。

在文件startup_stm32f10x*.c有一章节:

/*----------Stack Configuration----------*/ 
#define STACK_SIZE  0x00000100  /*!< The Stack size suggest using even number  */ 

而在随后很下一行:

__attribute__ ((section(".co_stack"))) 
unsigned long pulStack[STACK_SIZE];  

我已经改变了这个值0x00000500,并得到了一切工作。

+1

如果您希望在不同的地址使用,您仍然应该能够通过链接脚本调整'.co_stack'的位置。 –

+0

@MattMcNabb,栈无论如何都有固定的大小,所以这里没有把它放在特定的位置(即使在SRAM的末尾),因为链接器可以在堆栈开始之前直接放置其他一些变量。无论如何感谢您的通知。 – desertkun

3

GNU工具链使用目标特定链接描述文件(c通常使用.ld文件扩展名)。这将描述你的目标的内存布局,并可以定制以适应。

推导堆栈和堆位置的方式有点不确定和过于复杂。查看链接器生成的映射文件输出(ld命令行选项-Map <mapfile>)非常简单且完全准确。

堆是通过定义动态分配,所以隐含不使用分配静态数据;这是你的误解。链接器将在构建时分配静态数据位置。链接器脚本可能会分配一个固定大小的堆栈,然后分配剩下的所有内容,而不是保留用于其他目的的堆。定制脚本还可以为其他目的分配区域,例如DMA缓冲区或电池支持域。

无论哪种方式,放置堆栈几乎不可能是解决您的实际问题;这只是让事情发生;它不会增加可用内存;任何堆栈溢出都会与其他东西发生冲突。

+0

为什么每次都会在同一个地方发生内存冲突,不管A'有多大?我很乐意错误,但从我的角度来看,内存映像看起来像[这个映像](http://prntscr.com/7hd0t7)。 – desertkun

+0

@desertkun:我不确定我是否理解你的插图,但不需要猜测存储器映射是什么;链接器脚本会告诉你内存的静态组织,链接图文件会告诉你确切的地址。你的图确实存在静态数据存在于堆中的谬论;它不是。链接图也会告诉你静态数据的准确地址。然而,我猜想堆大小会减小以适应更大的静态数据 - 堆基地址增加,但堆栈顶部保持不变,因为堆栈是固定的。 – Clifford