STM32中断处理器未声明时链接器 fallback 至Default_Handler原因问询
中断处理器已实现却跳转至Default_Handler的原因
问题背景
近期排查了一个UART1中断相关的问题,场景如下:
- MCU启动文件中定义的中断向量表及弱符号:
g_pfnVectors: [...some lines removed] .word USART1_IRQHandler [...more lines removed]
.weak USART1_IRQHandler .thumb_set USART1_IRQHandler,Default_Handler
- 在
stm32wlxx_it.cpp中实现了中断处理器,但未在对应头文件中添加声明:
void USART1_IRQHandler(void) { uint32_t isrflags = USART1->ISR; if (isrflags & uart1::rdrNotEmpty) { uart1::rxNotEmpty(); } if (isrflags & uart1::tdrEmpty) { uart1::txEmpty(); } }
- 项目编译链接无错误,但中断触发时,代码跳转至启动文件中的
Default_Handler死循环:
.section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop .size Default_Handler, .-Default_Handler
疑问:为何已实现中断处理器但未加声明时,链接器会 fallback 至Default_Handler?
原因解析
核心是C++名字修饰机制与汇编弱符号规则共同作用的结果:
- 启动文件里用汇编定义的
.weak USART1_IRQHandler是C风格的未修饰符号,链接器会按这个原始名字去查找对应的函数实现。 - 你在
.cpp文件里写的USART1_IRQHandler是C++函数,编译器会对其进行名字修饰(比如生成类似_Z16USART1_IRQHandlerv的符号名),这个修饰后的名字和汇编里的弱符号完全不匹配。 - 链接器找不到与
USART1_IRQHandler匹配的强符号,就会启用启动文件中定义的弱符号版本——也就是绑定到Default_Handler的默认实现。 - 编译链接无报错的原因:.cpp文件内的函数是内部实现,编译器不会报错;弱符号的存在让链接器认为符号已定义,只是使用了默认的弱实现,因此也不会抛出错误。
修复方案
有两种常用解决方式:
- 直接在C++文件中用
extern "C"包裹中断函数,强制编译器按C风格生成未修饰的符号:
extern "C" { void USART1_IRQHandler(void) { uint32_t isrflags = USART1->ISR; if (isrflags & uart1::rdrNotEmpty) { uart1::rxNotEmpty(); } if (isrflags & uart1::tdrEmpty) { uart1::txEmpty(); } } }
- 在头文件中用
extern "C"声明该函数,然后在.cpp文件中实现,确保跨文件引用时符号一致:
// stm32wlxx_it.h extern "C" void USART1_IRQHandler(void);
内容的提问来源于stack exchange,提问作者Strooom
相关产品推荐
相关产品推荐

