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

STM32中PIC程序函数内静态变量未通过.got表寻址的解决问询

问题描述

我正在为STM32微控制器的Bootloader+双分区固件FOTA策略实现位置无关代码(PIC)。当固件被Bootloader加载到链接脚本指定外的地址时,只要Bootloader正确重映射中断表并加载正确的.got段偏移,固件可正常启动。但访问.bss段内的函数局部静态变量时地址错误,发现这些变量未通过.got表寻址,而是采用PC偏移方式,破坏了位置无关性。全局变量(含.bss段的)可通过.got表正常访问。

我使用GCC编译,已添加-fpic、-msingle-pic-base、-fno-jump-tables选项,尝试添加-mpic-data-is-text-relative但无效。请问是否有办法让所有函数局部静态变量像全局数据一样通过.got表映射,以确保代码位置无关性?

编译选项

-mcpu=cortex-m33 -std=gnu11 -g3 -DDEBUG -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER -DSTM32H563xx -c -I../Core/Inc -I../Drivers/STM32H5xx_HAL_Driver/Inc -I../Drivers/STM32H5xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32H5xx/Include -I../Drivers/CMSIS/Include -I"C:\Repos\bootloader_test\BootloaderTest\Core\Shared" -O0 -ffunction-sections -fdata-sections -Wall -fno-jump-tables -fpic -msingle-pic-base -fstack-usage -fcyclomatic-complexity --specs=nano.specs -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb

链接脚本片段

.got段定义

.got (APP_GOT_START):
{
  . = ALIGN(4);
  GOT_START = .;
  KEEP(*(.got)) 
  GOT_END = .;
  . = ALIGN(4);
} >APP_GOT AT> APP_B_GOT

.bss段定义

.bss (APP_RAM_START):
{
  . = ALIGN(4);
  /* 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

解决方案

1. 调整编译选项强制局部静态变量走GOT表

GCC默认对函数局部静态变量采用PC相对寻址,需添加以下选项修改行为:

-fpic -mpic-register=r9 -mno-pic-data-is-text-relative
  • -mpic-register=r9:指定R9作为PIC基址寄存器,确保所有数据访问通过基址寄存器偏移计算。
  • -mno-pic-data-is-text-relative:禁止数据采用文本段相对的PC寻址,强制全局、局部静态变量均通过GOT表访问。
  • 保留原有的-msingle-pic-base,确保整个程序仅使用一个PIC基址,简化Bootloader的偏移加载逻辑。

2. 修改链接脚本,覆盖局部静态变量的段规则

函数局部静态变量默认会被归入.gnu.linkonce.b.*(未初始化)或.gnu.linkonce.d.*(已初始化)子段,需在链接脚本中显式包含这些段,并确保GOT表能捕获其引用:

更新.bss段定义

.bss (APP_RAM_START):
{
  . = ALIGN(4);
  _sbss = . ;
  __bss_start__ = _sbss ;
  *(.bss)
  *(.bss*)
  *(.gnu.linkonce.b.*)  /* 显式包含局部静态未初始化变量的子段 */
  *(COMMON)

  . = ALIGN(4);
  _ebss = .;
  __bss_end__ = _ebss;
} >RAM

更新.got段定义

.got (APP_GOT_START):
{
  . = ALIGN(4);
  GOT_START = .;
  KEEP(*(.got))
  KEEP(*(.got.plt))
  KEEP(*(.gnu.linkonce.got.*))  /* 捕获局部静态变量的GOT引用条目 */
  GOT_END = .;
  . = ALIGN(4);
} >APP_GOT AT> APP_B_GOT

3. 代码层强制变量属性(应急方案)

如果编译/链接脚本调整无效,可给局部静态变量添加属性,强制编译器将其按全局变量处理:

void test_func(void)
{
  // 强制变量通过GOT表寻址
  static uint32_t static_var __attribute__((visibility("hidden")));
  static_var++;
}

该方法需逐个修改变量,适合小范围验证或临时修复。

4. 升级GCC版本

部分旧版GCC对Cortex-M系列的PIC支持存在缺陷,建议升级到GCC 10及以上版本,新版本对局部静态变量的PIC处理逻辑更严谨,能更好适配-fpic选项。


内容的提问来源于stack exchange,提问作者Matteo Vittorio Ricciutelli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:31:36