GNU LD linker script - stack placement
这是我的STM32L476链接程序脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | /* Generate a link error if heap and stack don't fit into RAM */ __heap_size = 0x200;; /* required amount of heap */ __stack_size = 0x800;; /* required amount of stack */ /* Specify the memory areas */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 96K } /* Define output sections */ SECTIONS { /* The startup code goes first into FLASH */ .default_exceptions : { . = ALIGN(8); KEEP(*(.default_exceptions)) /* Startup code */ . = ALIGN(8); } >FLASH /* The program code and other data goes into FLASH */ .text : { . = ALIGN(8); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) . = ALIGN(8); _etext = .; /* define a global symbols at end of code */ } >FLASH /* Constant data goes into FLASH */ .rodata : { . = ALIGN(8); *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(8); } >FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } >FLASH .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); } >FLASH .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); } >FLASH .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); } >FLASH /* The startup code goes first into FLASH */ .exceptions : { . = ALIGN(8); KEEP(*(.exceptions)) /* RAM vector table */ . = ALIGN(8); } >RAM /* used by the startup to initialize data */ _sidata = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code */ .data : { . = ALIGN(8); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(8); _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH /* Uninitialized data section */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; /* define a global symbol at bss start */ *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ } >RAM /* User_heap_stack section, used to check that there is enough RAM left */ .heap : { . = ALIGN(4); PROVIDE ( end = . ); _sheap = .; . = . + __heap_size; . = ALIGN(4); _eheap = .; } >RAM .stack : { . = ALIGN(4); _estack = .; . = . + __stack_size; . = ALIGN(4); _sstack = .; } >RAM .ARM.attributes 0 : { *(.ARM.attributes) } } |
对应的地图文件是:
1 2 3 4 5 6 7 | .stack 0x20002844 0x800 load address 0x0801cc68 0x20002844 . = ALIGN (0x4) 0x20002844 _estack = . 0x20003044 . = (. + __stack_size) *fill* 0x20002844 0x800 0x20003044 . = ALIGN (0x4) 0x20003044 _sstack = . |
我想对其进行修改,以使堆栈位于RAM的末尾。
我尝试了几种方法(包括此处讨论的方法,但是没有用。即使添加硬编码的地址也将返回错误(该芯片上的RAM达到0x20018000,因此应该可以容纳):
1 2 3 4 5 6 7 8 | .stack : { . = 0x20001000; _estack = .; . = . + __stack_size; . = ALIGN(4); _sstack = .; } >RAM |
错误是:
1 2 3 4 5 6 7 | 20:01:46 **** Build of configuration Debug for project CardioNexion **** make app=unit_test board=nucleo-l476rg V=1 all c:/program files (x86)/atollic/truestudio for stm32 9.0.0/armtools/bin/../lib/gcc/arm-atollic-eabi/6.3.1/../../../../arm-atollic-eabi/bin/ld.exe: region `RAM' overflowed by 536789060 bytes collect2.exe: error: ld returned 1 exit status make: *** [link] Error 1 20:01:50 Build Finished (took 4s.3ms) |
任何想法都可能导致此问题,以及如何做到这一点? (将堆栈放在ram的末端)。
这种"传统"方法对于裸机开发不是很好。
更好的方法是将堆栈放在RAM的开头。没有静默变量被覆盖的危险,堆栈溢出将产生异常-它的例程可以采取适当的措施(例如,将设备切换到"安全"模式,重新启动,紧急停止受控机器等)。
如果要将堆栈放在RAM顶部,可以在链接程序脚本中使用简单的算法,如下所示(已简化):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 96K } SECTIONS { __stacktop = ORIGIN(RAM) + LENGTH(RAM); . = ORIGIN(FLASH); .text : { KEEP(*(.stack)) KEEP(*(.vectors)) KEEP(*(.text)) . = ALIGN(4); KEEP(*(.rodata)) . = ALIGN(4); } >FLASH .data ALIGN(4) : { __data_start = .; *(.data) . = ALIGN(4); __data_end = .; } >RAM AT >FLASH .bss ALIGN(4) (NOLOAD) : { __bss_start = .; *(.bss) . = ALIGN(4); __bss_end = .; } >RAM . = ALIGN(4); __heap_start = .; } |
重要的是要在闪存的开始处添加
启动文件之一:
1 2 3 4 5 | // top of stack extern unsigned __stacktop; // initial stack pointer is first address of program __attribute__((section(".stack"), used)) unsigned *__stack_init = &__stacktop; |
所有未使用的RAM将从一侧用于HEAP,从另一侧用于STACK。
简单而完整的示例在这里:https://github.com/cortexm/baremetal。