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

嵌入式C中如何通过链接器将结构体精确定位到指定内存地址?

问题根源与修复方案

核心问题

  1. const变量的段归属错误:你定义的const conf_t gv_confReg是只读常量,GCC等嵌入式编译器会默认将全局const变量放入.rodata段(只读数据段),而非你链接脚本中配置的.data段,因此链接器不会将其映射到0x40000000地址。
  2. 链接脚本配置不匹配:你的链接脚本仅对.data段做了地址映射,未处理.rodata段;且原脚本中.data段的ADDR属性写法冗余(> PROM已指定内存区域,无需额外ADDR)。
  3. 未初始化结构体:仅声明const conf_t gv_confReg但未初始化,编译器可能将其标记为未使用符号或放入未初始化段,导致地址不可控。

修复步骤

1. 显式指定变量的段并初始化结构体

修改config.c,通过编译器属性将变量放入自定义段,同时必须初始化结构体(避免编译器优化):

const conf_t gv_confReg __attribute__((section(".conf_section"))) = {
    .val1 = 0x12345678,
    .val2 = 0x87654321
};

2. 修改链接器脚本,映射自定义段到指定地址

更新linker.ld,将自定义的.conf_section段放在0x40000000起始位置,同时保留其他必要段的配置:

MEMORY 
{
    PROM (r) : ORIGIN = 0x40000000, LENGTH = 256k
}

SECTIONS 
{
    . = ORIGIN(PROM);
    // 优先放置配置结构体,确保起始地址精确为0x40000000
    .conf_section : {
        KEEP(*(.conf_section))  // 防止链接器丢弃该段
    } > PROM

    // 处理其他只读数据段
    .rodata : {
        *(.rodata)
        *(.rodata.*)
    } > PROM

    // 处理读写数据段
    .data : {
        *(.data)
        *(.data.*)
    } > PROM

    .init_array : {
        PROVIDE(__init_array_start = .);
        KEEP(*(.init_array))
        PROVIDE(__init_array_end = .);
    } > PROM
}

如果不想用自定义段,也可以直接将.rodata段放在起始位置,但自定义段更灵活,不会影响其他只读数据的布局。

3. 验证地址正确性

编译完成后,通过以下方式验证:

  • 查看生成的out.map文件,搜索gv_confReg确认地址;
  • 使用objdump工具反编译二进制文件:
    objdump -t your_output_binary | grep gv_confReg
    
    正常情况下会显示地址为0x40000000。

额外注意事项

  • 若开启了-fdata-sections或-ffunction-sections编译选项,必须用KEEP()确保目标段不被链接器丢弃;
  • const全局变量必须初始化,否则编译器可能不为其分配实际内存;
  • 链接脚本中> PROM已指定运行地址(VMA),若PROM是运行时直接访问的存储介质,无需额外设置ADDR属性(该属性用于指定加载地址LMA,通常用于需要拷贝数据到RAM的场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:05:06