ARM Cortex-M3使用GNU工具链高优化级别触发总线故障问题咨询
结论:这不是GNU工具链的Bug,是代码类型错误触发了编译器优化异常
核心问题:原memset的参数类型违反C标准
你的原始memset函数声明存在致命错误:
void* memset(void s, int c, size_t len){
第一个参数s被声明为void类型——这在C标准中是非法的(仅允许函数返回值为void,函数参数不能直接使用void类型,正确的指针参数应该是void *s)。
这种错误的类型声明会让编译器对函数的参数解析完全混乱,在高优化级别(-O2/-O3/-Os)下,编译器的优化逻辑基于错误的类型信息,最终生成了递归调用自身的汇编代码(bl memset),导致栈溢出触发STKERR,同时错误的内存访问引发PRECISERR。
为什么-Og下能正常运行?
-Og是专为调试设计的优化级别,编译器仅执行最少的优化,会尽可能贴合你写的代码逻辑生成汇编,因此即使参数类型错误,它依然按照循环赋值的逻辑生成了可运行的代码。而高优化级别下,编译器会尝试对代码进行更激进的变换,错误的类型信息直接导致了优化逻辑走偏。
关于volatile的作用
你修改后的代码中,添加volatile确实解决了问题,但真正的修复是修正了参数类型为void *s——volatile只是进一步限制了编译器对变量的优化,避免了潜在的误判,但核心问题是原始代码的参数类型错误。如果只修正参数类型而不加volatile,高优化级别下也会生成正确的非递归汇编。
验证:修正参数类型后的正确行为
将原始代码的参数修正为标准的void *s:
void* memset(void *s, int c, size_t len){ unsigned char *dst; dst = (unsigned char *) s; while (len > 0) { *dst = (unsigned char) c; dst++; len--; } return s; }
使用-O2编译后,编译器会生成类似-Og的循环赋值汇编,不会出现递归调用,总线故障也会消失。
内容的提问来源于stack exchange,提问作者user3786632
相关产品推荐
相关产品推荐

