Search code examples
llvmcortex-mlld

LLVM linker places stack in the wrong place


I am trying to link Cortex-M4 firmware with clang + lld. The gcc build works fine. I am using the stock CMSIS linker script with only RAM & ROM size adjusted (bases are the same). Beginning of the script (without comments):

__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
}

Linking fails on the assert ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") at the very end of the script. If I remove the assert the binary links fine, but stack is at a wrong address. It ends up in flash (heap is also in the wrong place). Output from 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

The code of course crashes when trying to run on the Cortex-M. I found this ticket. If I change my .stack section to:

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

then I am getting overflow errors:

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

That huge number is 0x200020A8 so the lld probably gets the end address correctly, but not the origin.

How can I fix the linker script to place the stack correctly at top of RAM? Thanks for help


Solution

  • I fixed it by removing COPY and adding NOLOAD to the stack section. It builds and runs fine both with gcc and clang.

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