STM32F103ZETx_FLASH.ld 解析

  • STM32F103ZETx_FLASH.ld 是一个脚本文件,用于定义 STM32F103ZETx 微控制器的内存布局和链接过程
    • startup_stm32f103x3.s 文件使用本文件中定义的符号
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
******************************************************************************
**
** @file : LinkerScript.ld
**
** @author : Auto-generated by STM32CubeIDE
**
** @brief : Linker script for STM32F103ZETx Device from STM32F1 series
** 512Kbytes FLASH
** 64Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
******************************************************************************
** @attention
**
** Copyright (c) 2023 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
}

/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH

/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.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(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH

/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH

.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH

.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH

.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH

.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH

.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH

/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);

/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */

. = ALIGN(4);
_edata = .; /* define a global symbol at data end */

} >RAM AT> FLASH

/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)

. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM

/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM

/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}

.ARM.attributes 0 : { *(.ARM.attributes) }
}
1
2
/* Entry Point */
ENTRY(Reset_Handler)
  • 定义了程序的入口点,微控制器启动时先调用 Reset_Handler 函数,函数实现在 startup_stm32f103xe.s 中
1
2
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
  • (固定值)栈从高地址向低地址增长,所以栈顶(RAM的末尾)为起始点
1
2
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
  • (自定义)堆和栈所需的最小空间
1
2
3
4
5
6
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
}
  • 0x20000000 是 STM32F1 系列 SRAM(也就是 RAM)的物理起始地址
  • 0x08000000 是片上主闪存(FLASH)的物理起始地址
  • 64K 和 512K 是你这颗 ZET6 型号芯片的 RAM 和 FLASH 容量
1
2
3
4
5
6
7
8
9
10
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
  • 定义了中断向量表段。
  • KEEP 命令告诉链接器即使认为这个段没被使用也不能丢弃。
  • FLASH 表示把整个段放入 MEMORY 中定义的 FLASH 区域。

  • 当BOOT/Option Bytes 配置为从 Main Flash 启动时,中断向量表位于 FLASH 的最开始位置,因为芯片硬件设计就是上电后去 0x08000000 这个地址开始找它,但向量表位置也可通过VTOR寄存器在运行时重定向,因此只需要保证 .isr_vector 放在FLASH 区域,通常放在首部。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.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(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
  • 用于存放程序代码,并将其放入 FLASH
  • *(.glue_7) 和 *(.glue_7t): 收集用于ARM和Thumb指令集之间相互跳转的“胶水代码”。.glue_7 / .glue_7t 是由编译器在 ARM/Thumb 模式跳转时自动插入的小段跳转桥。虽然 Cortex-M3 仅支持 Thumb-2 指令集,但 GCC 仍保留该段用于兼容库。
  • *(.eh_frame): 含有异常处理和回溯表信息,C++ ,调试工具(GDB…)进行栈回溯.
  • KEEP((.init)) 和 KEEP((.fini)): 保留C++构造函数和析构函数的相关代码段。
  • _etext = .;: 定义一个名为 _etext 的符号,其值为当前地址,即 .text 段的结束地址。
1
2
3
4
5
6
7
8
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
  • 定义了 .rodata(只读数据,如 const 变量和字符串常量)段。
  • 代码和只读数据在程序运行期间不会改变,所以它们理应被存放在非易失性的 FLASH 存储器中。
1
2
3
4
5
6
7
8
9
10
11
12
13
.ARM.extab   : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH

.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
  • 存放 ARM 架构相关的异常处理表信息,这两个段遵从 ARM EHABI 标准,为任何异常提供回溯索引,C 与 C++ 均可使用。
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
.preinit_array     :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH

.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH

.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
  • 这三个段用于支持 C++ 的全局对象的构造函数和析构函数
  • .init_array 里的函数指针会在 main 函数执行前被调用(用于构造)
  • .fini_array 里的会在程序退出时被调用(用于析构)。
1
2
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
  • 返回 .data 段加载到FLASH的起始地址, 这个符号将被启动代码用来作为数据拷贝的源地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */

. = ALIGN(4);
_edata = .; /* define a global symbol at data end */

} >RAM AT> FLASH
  • 定义了 .data 输出段,用于存放已初始化的全局变量和静态变量
  • RAM: 这是运行时地址 (VMA - Virtual Memory Address) 指令。它告诉链接器,当程序运行时,这些变量位于 RAM 内存区域。因为变量需要在运行时被读写,所以必须在RAM中。

  • AT> FLASH: 这是加载时地址 (LMA - Load Memory Address) 指令。它告诉链接器,在生成最终的二进制文件时,请把这些变量的初始值存放到 FLASH 内存区域。
  • _sdata = .;: 定义符号 _sdata,其值为 .data 段在 RAM 中的起始地址。它将作为启动代码中数据拷贝的目的地址。
  • *(.RamFunc) 和 (.RamFunc): 收集被指定要在RAM中运行的函数。
  • _edata = .;: 定义符号 _edata,其值为 .data 段在 RAM 中的结束地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)

. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
  • 定义 .bss (Block Started by Symbol) 输出段,用于存放未初始化的全局变量和静态变量。
  • RAM: 它只有一个 >RAM 指令,没有 AT> 指令。这意味着链接器只在 RAM 中为这些变量预留空间,但不会在 FLASH 文件中为它们存储任何数据,从而节省了 FLASH 空间。

  • _sbss = .; 和 _ebss = .;: 定义了 .bss 段在 RAM 中的起始和结束地址。启动代码会使用这两个地址,将这块内存区域清零。
  • *(COMMON): 收集那些在C语言中未初始化的、但可能在多个文件中被声明的“公共”变量。
1
2
3
4
5
6
7
8
9
10
/* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
  • 不包含输入文件的内容,用于链接期检查和定义堆起始地址。
  • PROVIDE ( end = . );: PROVIDE 表示如果外部代码没有定义 end 这个符号,就在这里定义它。end 和 _end 通常被C库用来标记堆的起始位置。此时 . 的值是 .bss 段的结束地址。
  • . = . + _Min_Heap_Size;: 将当前地址向后移动 _Min_Heap_Size 大小,模拟分配堆空间。
  • . = . + _Min_Stack_Size;: 再向后移动 _Min_Stack_Size 大小,模拟分配栈空间。
  • 核心作用: 如果 . 的最终值超过了 RAM 的边界 (0x20010000),链接器会报错,从而实现了在编译阶段就检查出RAM溢出的问题。
  • 栈从 _estack 向下增长,堆自下向上增长。
1
2
3
4
5
6
7
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
  • 特殊的丢弃段。所有被放入这个段的内容都会从最终的输出文件中被移除。这里移除了C库、数学库和GCC支持库中的所有内容,这通常是一个过于激进的优化,但在某些极简的裸机项目中可能会使用。对于我们使用的CubeMX生成的项目,通常会有更精细的垃圾回收(–gc-sections),这个 DISCARD 段可能不起主要作用。
1
.ARM.attributes 0 : { *(.ARM.attributes) }
  • 定义一个输出段 .ARM.attributes。这是一个信息段,它存储了关于编译选项、ABI(应用程序二进制接口)版本等元数据。链接器会用这些信息来检查所有输入的目标文件是否相互兼容。0 是该段的类型标识。这是一个现代ARM工具链的标准组成部分。
    }

  • SECTIONS 语句定义了链接器应创建的输出段

作者

GoKo Mell

发布于

2024-05-02

更新于

2025-11-03

许可协议

评论

:D 一言句子获取中...