Cortex-M7平台GCC编译位置无关代码(PIC)的全局指针偏移问题
现有一批需在Cortex-M7嵌入式系统中编译为位置无关代码(PIC)的C代码,原使用ARMCC编译器并添加--ropi --rwpi选项可正常运行。现需切换至GCC 12.2版本编译,加载代码的ThreadX Modules系统约定使用r9作为全局偏移表(GOT)的偏移寄存器,参考编译选项为:-fpie -fno-plt -mno-pic-data-is-text-relative -msingle-pic-base,无特殊链接选项。
当前核心问题:GCC编译后,全局变量地址获取逻辑失效,ARMCC下无此问题。示例代码及输出如下:
示例代码
char buffer[100]; char* pBuffer = buffer; int appModMain() { printf("buffer address: %p, buffer address via pBuffer: %p\n", buffer, pBuffer); }
输出结果
buffer address: 60C8C25C, buffer address via pBuffer: 1000025C
可见直接取buffer地址能得到正确的偏移后地址,但通过全局指针pBuffer获取的地址未应用偏移。反汇编证实:加载pBuffer到寄存器传递给printf时,未使用r9寄存器进行必要的偏移调整;且pBuffer被初始化为buffer的未偏移地址,编译器虽识别pBuffer指向GOT内容,但生成代码时未添加偏移处理。
已尝试-mpic-data-is-text-relative/-mno-pic-data-is-text-relative、-msingle-pic-base/-mnosingle-pic-base等选项的多种组合,均无效果。因代码量庞大且包含非自研模块,无法修改源码,需寻求GCC适配的解决方案。
以下为针对该问题的可行调整方案:
指定PIC基址寄存器为r9
GCC默认使用r10作为ARM架构下的PIC基址寄存器,而ThreadX Modules系统约定使用r9。需添加编译选项-mpic-register=r9,强制GCC使用r9作为全局偏移表的基址寄存器,与系统约定对齐。完善编译与链接选项
将编译链接选项调整为:-fpie -pie -fno-plt -mno-pic-data-is-text-relative -msingle-pic-base -mpic-register=r9其中
-pie用于链接阶段生成位置无关可执行文件,确保重定位逻辑正确生效;-mpic-register=r9确保GCC生成的代码使用r9进行偏移计算。强制全局变量进入非common段
添加-fno-common编译选项,强制全局变量(包括初始化的指针变量pBuffer)进入非common存储段,让编译器生成正确的重定位条目,确保加载时通过r9完成地址偏移。检查链接脚本的重定位配置
若上述选项仍无效,需确认链接脚本中是否正确处理RWPI数据的重定位:- 确保
.data、.bss等可重定位段使用REL类型的重定位条目; - 确认GOT表的生成逻辑符合ThreadX Modules的要求;
- 可添加链接选项
-Wl,--verbose查看链接过程,排查GOT相关重定位是否正确生成。
- 确保
内容的提问来源于stack exchange,提问作者Rob

