调用__udivsi3触发MSPM0C1104硬故障,如何将写入操作移至RAM?
MSPM0C1104调用__udivsi3触发硬故障问题
故障现象
调用__udivsi3函数时触发硬故障:进入该函数后经过几次跳转,尝试在Flash区域(地址0x992)执行.word 0xff1ee8bd操作,直接触发硬故障。
复现情况
- 复现代码:
实际运算值来自控制器库的可配置宏/变量,其他除法运算也能复现该问题。volatile uint32_t test; test = 24000000; test /= 24000000; - 无论函数是否添加
__attribute__((optimize("-O0"))),或者使用-O2优化,故障都会出现。
链接器内存段配置
FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00003BFF SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00000400 DEVICE_CONFIG (RW!x) : ORIGIN = 0x00003C00, LENGTH = 0x000001FF BCR_CONFIG (R) : ORIGIN = 0x41C00000, LENGTH = 0x000000FF
编译器设置
"C:/TI/gcc_arm_none_eabi_9_2_1/bin/arm-none-eabi-gcc-9.2.1.exe" -c @"device.opt" -mcpu=cortex-m0plus -march=armv6-m -mthumb -mfloat-abi=soft -I"C:/TI/mspm0_sdk_2_09_00_01/source/third_party/CMSIS/Core/Include" -I"C:/TI/mspm0_sdk_2_09_00_01/source" -I"C:/MYPROJ/src" -I"C:/MYPROJ/src/modules" -I"C:/MYPROJ/src/modules/comp1" -I"C:/MYPROJ/src/modules/communication" -I"C:/MYPROJ/src/modules/mylib" -I"C:/MYPROJ/src/modules/battery" -I"C:/MYPROJ/src/modules/accelerometer" -I"C:/MYPROJ" -I"C:/MYPROJ/Debug" -O2 -ffunction-sections -fdata-sections -gdwarf-3 -gstrict-dwarf -Wall -fno-math-errno -MMD -MP -MF"src/modules/communication/communication.d_raw" -MT"src/modules/communication/communication.o" -std=c99 @"./device.opt" -o"src/modules/communication/communication.o" "../src/modules/communication/communication.c"
链接器设置
"C:/TI/gcc_arm_none_eabi_9_2_1/bin/arm-none-eabi-gcc-9.2.1.exe" @"device.opt" -O2 -ffunction-sections -fdata-sections -gdwarf-3 -gstrict-dwarf -Wall -fno-math-errno -mthumb -mfloat-abi=soft -Wl,-Map,"myproj.map" -nostartfiles -nostdlib -static -Wl,--gc-sections -L"C:/TI/mspm0_sdk_2_09_00_01/source/ti/driverlib/lib/gcc/m0p/mspm0c110x" -L"C:/TI/mspm0_sdk_2_09_00_01/source" -L"C:/MYPROJ" -L"C:/MYPROJ/Debug/syscfg" -L"C:/TI/gcc_arm_none_eabi_9_2_1/lib/gcc/arm-none-eabi/9.2.1" -L"C:/TI/gcc_arm_none_eabi_9_2_1/arm-none-eabi/lib/thumb/v6-m/nofp" -march=armv6-m -mthumb --specs=nano.specs -o"myproj.out" "./ti_msp_dl_config.o" "./startup_mspm0c110x_gcc.o" "./main.o" "./src/modules/accelerometer/accelerometer.o" "./src/modules/battery/battery.o" "./src/modules/mylib/communication/communication.o" "./src/modules/rear_light/comp1.o" -Wl,-T"../make/myproj.lds" -Wl,-Tdevice.lds.genlibs -lm -lgcc -lc -l:driverlib.a
相关映射信息
.text 0x000004e8 0x114 C:/TI/gcc_arm_none_eabi_9_2_1/lib/gcc/arm-none-eabi/9.2.1\libgcc.a(_udivsi3.o) 0x000004e8 __aeabi_uidiv 0x000004e8 __udivsi3
最小复现代码
// 控制器配置头文件,示例即使不显式包含也能运行 #include "ti_msp_dl_config.h" #include <stdint.h> int main (void) { volatile uint32_t test; test = 24000000; test /= 100; // 执行到该行后触发硬故障 while(1); }
核心问题
- 为什么GCC ARM库会将写入操作放在Flash中?
- 如何将这些写入操作移至RAM?
问题解答
原因分析
Cortex-M0+架构没有硬件除法指令,GCC会调用__udivsi3(对应无符号32位除法)这类软件除法库函数。你使用的9.2.1版本GCC ARM库实现中,__udivsi3采用了位置无关代码(PIC)的实现方式,会在函数内部尝试向当前代码段(Flash)写入临时指令——但Flash是只读存储,直接写入会触发内存访问错误,导致硬故障。同时你的链接器配置中FLASH段仅标记为RX(只读可执行),无写权限,进一步触发故障。
解决方法
升级GCC ARM工具链
10.x及以上版本的GCC ARM已经修复了该问题,软件除法函数会使用栈(RAM)存放临时数据,不再尝试写入Flash。直接替换为TI提供的新版本工具链即可解决。将除法库函数移至RAM执行
修改链接脚本,指定__udivsi3等相关函数存放到RAM段:- 在链接脚本中添加:
PROVIDE(__start_ram_functions = .); .ram_functions : { *libgcc.a(_udivsi3.o) *libgcc.a(_divsi3.o) *libgcc.a(__aeabi_uidiv.o) *libgcc.a(__aeabi_idiv.o) } > SRAM AT> FLASH PROVIDE(__end_ram_functions = .); - 在启动代码中添加复制逻辑,将
ram_functions段从Flash复制到RAM,确保函数运行前完成复制。
- 在链接脚本中添加:
禁用PIC库编译
编译时添加-fno-pic选项,强制GCC使用非位置无关的除法库实现,避免向Flash写入临时代码。替换为自定义除法函数
自行实现无符号32位除法函数,通过链接选项替换默认库函数:- 自定义函数示例:
uint32_t my_udivsi3(uint32_t num, uint32_t den) { if (den == 0) return 0; // 按需处理除零场景 uint32_t quotient = 0; while (num >= den) { num -= den; quotient++; } return quotient; } - 链接时添加
-Wl,--wrap=__udivsi3选项,让编译器使用自定义函数替代默认的__udivsi3。
- 自定义函数示例:
内容的提问来源于stack exchange,提问作者user32453993
相关产品推荐
相关产品推荐

