You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM Cortex-M3下GNU LD链接脚本LONG()未按预期放置值问题排查

问题描述

我在GNU ld链接脚本中添加了用于存储校验和的MEMORY定义:

_CRC_Value = 0x12345678;

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 80K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 524285 /* 范围到0x0807FFFB,按理说应该设为524284,但那样.map文件里的偏移就不对 */
  CHECKSUM (rw)   : ORIGIN = 0x807FFFC,    LENGTH = 4
}

并定义了如下段:

.crc :
{
  _Check_Sum = .; /* 把地址设为CHECKSUM区域的起始地址 */
  LONG(_CRC_Value);
} >CHECKSUM

我的.map文件显示内容似乎对齐正确(除非我理解有误):

.crc            0x0807fffc        0x4
                0x0807fffc                        _Check_Sum = .
                0x0807fffc        0x4 LONG 0x12345678 _CRC_Value

我曾在main.c中定义该符号:

uint32_t _Check_Sum __attribute__((section(".crc")));

不过后来将其注释掉了,因为链接器实际已定义该符号,无需重复定义。但无论是否注释,调试结果一致:

Expression | Type     | Value      | Address
_Check_Sum | uint32_t | 1450704896 | 0x807fffc

该值1450704896对应0x56780000,看起来像是2字节对齐问题,但我找不到原因。我曾认为内存边界计算有误,但当我将FLASH的LENGTH设为524284(我认为正确的值)时,.map文件显示所有内容偏移至0x807FFFB地址,且.crc段变为5字节。

我使用的是STM32F101 MCU(基于ARM Cortex-M3)。我认为这并非字节序问题,但也可能考虑不周。我尝试在.ld脚本的不同位置放置该段,唯一变化是.map文件中增加了ALIGN信息,显示位置计数器的下一个地址为0x08080000,这是正确的。

有没有人知道我遗漏了什么?


解决方案

1. 先修正FLASH长度的计算逻辑

STM32F101的512KB FLASH总字节数是524288,起始地址0x8000000,结尾地址是0x8000000 + 524288 = 0x8080000。要把CHECKSUM放在最后4字节(0x807FFFC~0x807FFFF),FLASH区域的长度应该设为524288 - 4 = 524284,对应范围是0x8000000~0x807FFFB,这个才是正确的。之前设524285会导致FLASH区域覆盖到0x807FFFC,和CHECKSUM区域重叠,这是引发地址分配异常的根源。

2. 为什么会出现0x56780000的错误值?

Cortex-M3是小端字节序,但这里不是字节序问题——你看到的0x56780000是因为数据只写入了低16位,高16位被清0。核心原因是FLASH区域结尾未做4字节对齐,链接器为了避免地址冲突,偷偷调整了.crc段的起始地址,但没保证4字节对齐,导致4字节的LONG值只成功写入低2字节,高2字节因地址不对被截断。

当FLASH长度设为524284时,0x8000000 + 524284 = 0x807FFFC,刚好是4字节对齐地址,CHECKSUM区域的起始地址0x807FFFC合法,不会出现偏移问题。

3. 链接脚本的具体调整

  • 把FLASH的LENGTH改为524284,确保和CHECKSUM区域无重叠且地址对齐;
  • 在.crc段定义里显式加4字节对齐指令,强制链接器保证地址合规:
.crc : ALIGN(4)
{
  _Check_Sum = .;
  LONG(_CRC_Value);
} >CHECKSUM
  • 不要在main.c里重复定义_Check_Sum,链接器已通过.crc段定义该符号,重复定义属于未定义行为,必须避免。

4. 验证要点

修改后重新编译,查看.map文件确认:

  • .crc段起始地址为0x807fffc,长度4字节,无区域重叠;
  • 调试读取_Check_Sum的值应为0x12345678(小端存储下内存字节顺序是0x78、0x56、0x34、0x12,但读取uint32_t变量时会自动转换为主机序,显示为0x12345678)。

内容的提问来源于stack exchange,提问作者Hunter Ritchie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:30:13