如何将堆栈对齐到 SRAM 的末尾?

Posted

技术标签:

【中文标题】如何将堆栈对齐到 SRAM 的末尾?【英文标题】:How can I align stack to the end of SRAM? 【发布时间】:2015-08-30 10:19:36 【问题描述】:

我有一个带有 48kb SRAM 的STM32F103VCT6 微控制器,最近我遇到了内存冲突:

我有一些静态变量(我们称之为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

所有静态变量(包括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)?

我正在使用带有 GNU Tools ARM Embedded 工具链的 CooCox IDE。

谢谢!

编辑:

对不起,这里有一些误解,A 不是 const,我之所以称它为静态只是因为关键字:

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

这说明A位于内存的开头:

A is at 20000c08

【问题讨论】:

为什么你认为静态变量是在堆上分配的?从您的结果来看,它们似乎更有可能位于内存顶部,堆栈从它们下方开始。尝试打印A 的地址。 这可能由您的链接描述文件控制。阅读(并阅读地图文件以查看结果) “我有一些静态变量(我们称之为 A)位于堆中” 这没有任何意义,所以问题也没有(为什么所有这些投票?)。静态变量和动态变量几乎是相互对立的,因此有“静态”和“动态”这两个词。静态变量分配在.data/.bss,动态变量在堆上,局部变量在栈上。现在,您是在谈论静态变量还是动态变量?因为他们不可能同时成为两者。请展示“A”的变量声明和初始化。 @Lundin 误会,更新问题 【参考方案1】:

我找到了原因:那是因为堆栈大小实际上是固定的,并且它位于堆中(如果我可以称它为堆)。

在文件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 并且一切正常。

【讨论】:

如果您希望 .co_stack 位于其他地址,您仍然应该能够通过链接描述文件调整其位置。 @MattMcNabb,栈的大小是固定的,所以这里没有必要将它放在特定的位置(即使在 SRAM 的末尾),因为链接器可以直接在栈的开头放置一些其他变量.无论如何感谢您的通知。【参考方案2】:

GNU 工具链使用特定于目标的链接器脚本(通常使用 .ld 文件扩展名)。这将描述您的目标的内存布局,并且可以根据需要进行定制。

您推断堆栈和堆位置的方式有些不确定且过于复杂。简单地查看链接器生成的映射文件输出(ld 命令行选项-Map &lt;mapfile&gt;)要简单得多且完全准确。

根据定义,堆是为动态分配的,所以隐式不用于分配静态数据;这是你的一个误解。链接器将在构建时分配静态数据位置。链接描述文件可能会分配一个固定大小的堆栈,然后将所有剩余的且未保留用于其他目的的堆栈分配给堆。自定义脚本还可以为其他目的分配区域,例如 DMA 缓冲区或电池支持的域。

无论哪种方式,堆栈的放置都不太可能解决您的实际问题;只是移动东西;它不会增加可用内存;任何堆栈溢出都会简单地与其他东西发生冲突。

【讨论】:

不管A多大,为什么每次都会在同一个地方发生内存冲突?我很乐意犯错,但从我的角度来看,内存映射看起来像 this image。 @desertkun :我不确定我是否理解您的说明,但无需猜测内存映射是什么;链接描述文件会告诉你内存的静态组织,链接映射文件会告诉你精确的地址。您的图表确实坚持了静态数据存在于堆中的谬误;它不是。链接图还会告诉您静态数据的准确地址。但是我猜想堆大小会减小以容纳更大的静态数据 - 堆基地址增加,但堆顶保持不变,因为堆栈是固定的。

以上是关于如何将堆栈对齐到 SRAM 的末尾?的主要内容,如果未能解决你的问题,请参考以下文章

StackView 对齐问题

CSS Flexbox:将最后第n个项目对齐到末尾[重复]

什么是“堆栈对齐”?

UIStackView 对齐问题

如何检测将显微镜图像旋转对齐到模板的良好特征

GCC - 如何重新对齐堆栈?