[ INFO ] start building at 2025-04-28 05:45:49 [ TOOL ] arm-none-eabi-gcc.exe (GNU Arm Embedded Toolchain 10-2020-q4-major) 10.2.1 20201103 (release) [ INFO ] file statistics (incremental mode) +---------+-----------+-----------+---------------+--------+ | C Files | Cpp Files | Asm Files | Lib/Obj Files | Totals | +---------+-----------+-----------+---------------+--------+ | 0 | 0 | 0 | 0 | 0 | +---------+-----------+-----------+---------------+--------+ [ INFO ] start compiling ... [ INFO ] start linking ... c:/users/administrator/.eide/tools/gcc_arm/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe:STM32F103C8TX_FLASH.ld:47: warning: redeclaration of memory region `RAM' c:/users/administrator/.eide/tools/gcc_arm/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe:STM32F103C8TX_FLASH.ld:48: warning: redeclaration of memory region `FLASH' c:/users/administrator/.eide/tools/gcc_arm/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe:d:/windows/HALproject/test5/STM32F103C8TX_FLASH.ld:88: non constant or forward reference address expression for section .ARM.extab collect2.exe: error: ld returned 1 exit status
时间: 2025-05-23 17:08:41 浏览: 28
### STM32F103C8TX_FLASH.ld 链接器脚本中的常见问题分析
在使用 `arm-none-eabi-gcc` 编译工具链处理 STM32F103C8 微控制器项目时,如果遇到链接器脚本文件(如 `STM32F103C8TX_FLASH.ld`)引发的 **内存区域重复声明警告** 和 **非恒定地址表达式错误**,通常是因为以下几个原因:
#### 1. 内存区域重复声明 (Redeclaration of Memory Region Warning)
当多个 `.ld` 文件定义了相同的内存区域名称时,可能会触发此警告。例如,在两个不同的地方都定义了一个名为 `FLASH` 的内存区域。
解决方案如下:
- 确保所有的内存区域名称唯一。
- 如果需要共享某些配置,则可以通过条件编译或者外部变量传递的方式实现统一管理[^1]。
以下是典型的 STM32F103C8T6 的内存布局示例代码片段:
```ld
MEMORY {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K /* Flash memory */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* SRAM */
}
```
#### 2. 非恒定地址表达式错误 (Non Constant Address Expression Error)
这种类型的错误通常是由于尝试动态计算某个符号的位置所引起的。比如下面的例子会报错:
```c
#define OFFSET 0x1000
__attribute__((section(".my_section"))) int my_var __attribute__((at(OFFSET)));
```
这里的问题在于 `OFFSET` 并不是一个真正的常量表达式,而是宏替换的结果。为了修复这个问题,可以改写成这样来确保它是静态解析的[^2]:
```c
int my_var __attribute__((section(".my_section"), at(0x1000)));
```
另外需要注意的是,GNU Linker 脚本本身不允许复杂的 C 表达式作为输入参数;因此任何涉及运行期变化的内容都需要提前转换为简单的数值形式再嵌入到汇编或连接阶段中去。
对于更复杂的情况可能还需要调整整个项目的构建流程以及依赖关系图以便更好地控制最终生成的目标二进制结构。
---
### 提供一段修正后的典型 LD Script 示例
假设我们正在针对 STM32F103C8 设备创建一个新的链接描述文档,那么它应该看起来像这样:
```ld
/* Entry Point Definition */
ENTRY(Reset_Handler)
SECTIONS{
.text :
{
*(.vectors) /* Vector Table */
*(.text*) /* Program Code */
*(.rodata*) /* Read Only Data */
} > FLASH
.data : AT (_etext){
_sdata = .;
*(.data);
_edata = .;
} >RAM
.bss :
{
_sbss = . ;
*(COMMON)
*(.bss*)
_ebss = . ;
} >RAM
}
/* Define symbols that can be used by startup code or other parts*/
_etext = ADDR(.text)+SIZEOF(.text);
_sstack = ORIGIN(RAM) + LENGTH(RAM);
_estack = _sstack - SIZEOF(STACK_SIZE);
PROVIDE(end = ._ebss);
```
以上例子展示了如何正确分配程序的不同部分至相应的存储区,并且通过一些辅助性的全局标识符帮助初始化过程完成堆栈指针设定等工作。
---
阅读全文
相关推荐







