关于gcc:GNU LD链接器脚本-堆栈放置

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 = .;
}

重要的是要在闪存的开始处添加KEEP(*(.stack)),然后在代码中将__stacktop放在此部分,如下所示:

启动文件之一:

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。