单片机/MCU论坛
直播中

陈超

8年用户 1018经验值
私信 关注
[问答]

Flash driver数据会随着代码修改而改变,怎么解决?

我们将Cy_FlashWriteCode放到了自定义段中
__attribute__ ((section(".cy_ramfunc"))) void Cy_FlashWriteCode(uint32_t writeAddr, const uint32_t* data, cy_en_flash_programrow_datasize_t size, cy_en_flash_driver_blocking_t blocking);
段的定义如下
代码编译后使用gmemfile工具将cy_ramfunc导出为bin文件
:postexec='gmemfile $(BIN_DIR_FROM_TOP_GPJ)$(PROGRAM_FILE_NAME) -start .cy_ramfunc -end .cy_ramfunc -o $(OUTPUTDIR)cy_ramfunc.bin'
现在问题是:即使修改和Cy_FlashWriteCode这个函数无关的代码,也会使编译出来的flash driver bin文件发生变化,这个应该怎么解决?怎么能让它不变?

回帖(1)

张龙祥

2025-8-18 16:40:41

针对Flash驱动函数Cy_FlashWriteCode在无关代码修改时其二进制内容(cy_ramfunc.bin)随之改变的问题,本质是链接地址变动导致的机器码差异。以下是系统的解决方案:




核心问题分析




  1. 地址敏感性

    函数Cy_FlashWriteCode中包含绝对地址引用(如全局变量地址、函数调用地址)。当其他代码修改导致内存布局变化时,这些引用地址随之改变,即使函数逻辑未变,其机器码也会不同。




  2. 链接器脚本未固定地址

    默认链接器脚本可能动态分配.cy_ramfunc段的地址,导致段基址随代码变动而偏移。






解决方案:固定地址 + PIC优化


1. 在链接脚本中固定段地址


修改链接器脚本(.ld文件),将.cy_ramfunc段分配到固定RAM地址


MEMORY {
    ... /* 原有内存区域定义 */
    RAM_FUNC (rwx) : ORIGIN = 0x20001000, LENGTH = 2K  /* 自定义固定地址区域 */
}

SECTIONS {
    ... /* 其他段 */

    .cy_ramfunc : {
        . = ALIGN(4);
        KEEP(*(.cy_ramfunc))   /* 强制保留段 */
        . = ALIGN(4);
    } > RAM_FUNC  /* 分配到固定区域 */
}

关键点



  • 选择一段未被占用且足够大的RAM区域(如0x20001000)。

  • 使用KEEP()确保段不被优化删除。




2. 移除函数中的绝对地址依赖


将函数改造为位置无关代码(PIC),使其可在任意地址运行:


__attribute__((section(".cy_ramfunc"), long_call, noinline))
void Cy_FlashWriteCode(...) {
    // 1. 替换全局变量访问为参数传递
    // 2. 避免直接调用外部函数,改用函数指针
    // 3. 使用相对跳转(编译器自动处理)
}

优化技巧



  • long_call:强制使用相对跳转指令。

  • noinline:防止内联破坏PIC属性。

  • 替换全局变量为参数(如通过结构体指针传入配置)。




3. 检查工具链导出命令


确保gmemfile导出命令严格限定段范围:


gmemfile $PROGRAM -start .cy_ramfunc -end .cycy_ramfunc_end -o cy_ramfunc.bin

在链接脚本中显式定义段结束符号:


.cy_ramfunc : {
    _start_cy_ramfunc = .;
    KEEP(*(.cy_ramfunc))
    _end_cy_ramfunc = .;
} > RAM_FUNC

导出时使用精确标记:


gmemfile ... -start _start_cy_ramfunc -end _end_cy_ramfunc ...



4. 验证一致性



  • 版本控制:对比不同构建的cy_ramfunc.bin哈希值。

  • 反汇编检查:确认修改后函数机器码在无关变更下是否稳定:
    arm-none-eabi-objdump -d build/app.elf --section=.cy_ramfunc




为什么此方案有效?



  1. 固定地址:消除基址偏移带来的机器码变化。

  2. PIC优化:移除对外部地址的依赖,使函数自包含。

  3. 精确导出:避免包含无关数据。



注意:若函数必须调用其他模块,将相关函数也放入.cy_ramfunc段,形成封闭环境。



通过地址固定+PIC改造,可确保cy_ramfunc.bin仅在驱动代码本身变更时更新,极大提升构建稳定性。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分