LLVM 链接器将堆栈放在错误的位置

LLVM linker places stack in the wrong place

我正在尝试 link 使用 clang + lld 的 Cortex-M4 固件。 gcc 构建工作正常。我正在使用 stock CMSIS linker 脚本,仅调整了 RAM 和 ROM 大小(基本相同)。脚本开头(无注释):

__ROM_BASE = 0x00000000;
__ROM_SIZE = 0x00040000; /* 256 KB */
__RAM_BASE = 0x20000000;
__RAM_SIZE = 0x00010000; /* 64 KB */
__STACK_SIZE = 0x00000400;
__HEAP_SIZE  = 0x00000C00;
MEMORY
{
  FLASH (rx)  : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
  RAM   (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
}

在脚本最后的断言 ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 上链接失败。如果我删除断言,二进制 link 没问题,但堆栈地址错误。它最终出现在闪存中(堆也在错误的位置)。来自 nm 的输出:

200018a8 B __bss_end__
200000d8 B __bss_start__
00004568 R __copy_table_end__
0000455c R __copy_table_start__
200000d4 D __data_end__
20000000 D __data_start__
00000000 ? __end__
00004570 A __etext
0000455c R __exidx_end
0000454c T __exidx_start
00000c00 A __HEAP_SIZE
00000c00 ? __HeapLimit
200000d4 d __init_array_end
200000d0 d __init_array_start
         w __libc_fini_array
00000445 T __libc_init_array
200000d0 d __preinit_array_end
200000d0 d __preinit_array_start
20000000 A __RAM_BASE
00010000 A __RAM_SIZE
00000000 A __ROM_BASE
00040000 A __ROM_SIZE
00000400 ? __stack
00000400 A __STACK_SIZE
00000000 ? __StackLimit
00000400 ? __StackTop

在 Cortex-M 上尝试 运行 时,代码当然会崩溃。我找到了this ticket。如果我将 .stack 部分更改为:

.stack (COPY) :
  {
    . = ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE;
    __StackLimit = .;
    . = . + __STACK_SIZE;
    . = ALIGN(8);
    __StackTop = .;
  } > RAM
  PROVIDE(__stack = __StackTop);

然后我收到溢出错误:

ld.lld: error: section '.stack' will not fit in region 'RAM': overflowed by 536879272 bytes

那个巨大的数字是 0x200020A8 所以 lld 可能正确地得到了结束地址,但不是起点。

如何修复 linker 脚本以将堆栈正确放置在 RAM 顶部?感谢帮助

我通过删除 COPY 并将 NOLOAD 添加到堆栈部分来修复它。它使用 gcc 和 clang 构建和运行良好。

 .stack (ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE) (NOLOAD) :
   {
    . = ALIGN(8);
    __StackLimit = .;
    . = . + __STACK_SIZE;
    . = ALIGN(8);
    __StackTop = .;
   } > RAM
   PROVIDE(__stack = __StackTop);