_ _weak关键字的作用

本文探讨了在编程中使用__weak关键字定义弱函数的方法,解释了如何通过该关键字允许用户在不修改原有函数的情况下重新定义同名函数,以及编译器在遇到未被用户重新定义的函数时的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

_ _weak关键字的作用

在函数名称前面加上_ _weak修饰符,称之为“弱函数”

用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数;若用户没有重新定义这个函数,则编译器就会执行_ _weak 声明的函数,并且编译器不会报错,所以我们可以在别的地方定义一个相同名字的函数,而不必也尽量不要修改之前的函数。

Default_Handler PROC EXPORT WWDG_IRQHandler [WEAK] EXPORT PVD_IRQHandler [WEAK] EXPORT TAMPER_IRQHandler [WEAK] EXPORT RTC_IRQHandler [WEAK] EXPORT FLASH_IRQHandler [WEAK] EXPORT RCC_IRQHandler [WEAK] EXPORT EXTI0_IRQHandler [WEAK] EXPORT EXTI1_IRQHandler [WEAK] EXPORT EXTI2_IRQHandler [WEAK] EXPORT EXTI3_IRQHandler [WEAK] EXPORT EXTI4_IRQHandler [WEAK] EXPORT DMA1_Channel1_IRQHandler [WEAK] EXPORT DMA1_Channel2_IRQHandler [WEAK] EXPORT DMA1_Channel3_IRQHandler [WEAK] EXPORT DMA1_Channel4_IRQHandler [WEAK] EXPORT DMA1_Channel5_IRQHandler [WEAK] EXPORT DMA1_Channel6_IRQHandler [WEAK] EXPORT DMA1_Channel7_IRQHandler [WEAK] EXPORT ADC1_2_IRQHandler [WEAK] EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK] EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK] EXPORT CAN1_RX1_IRQHandler [WEAK] EXPORT CAN1_SCE_IRQHandler [WEAK] EXPORT EXTI9_5_IRQHandler [WEAK] EXPORT TIM1_BRK_IRQHandler [WEAK] EXPORT TIM1_UP_IRQHandler [WEAK] EXPORT TIM1_TRG_COM_IRQHandler [WEAK] EXPORT TIM1_CC_IRQHandler [WEAK] EXPORT TIM2_IRQHandler [WEAK] EXPORT TIM3_IRQHandler [WEAK] EXPORT TIM4_IRQHandler [WEAK] EXPORT I2C1_EV_IRQHandler [WEAK] EXPORT I2C1_ER_IRQHandler [WEAK] EXPORT I2C2_EV_IRQHandler [WEAK] EXPORT I2C2_ER_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT SPI2_IRQHandler [WEAK] EXPORT USART1_IRQHandler [WEAK] EXPORT USART2_IRQHandler [WEAK] EXPORT USART3_IRQHandler [WEAK] EXPORT EXTI15_10_IRQHandler [WEAK] EXPORT RTCAlarm_IRQHandler [WEAK] EXPORT USBWakeUp_IRQHandler [WEAK] EXPORT TIM8_BRK_IRQHandler [WEAK] EXPORT TIM8_UP_IRQHandler [WEAK] EXPORT TIM8_TRG_COM_IRQHandler [WEAK] EXPORT TIM8_CC_IRQHandler [WEAK] EXPORT ADC3_IRQHandler [WEAK] EXPORT FSMC_IRQHandler [WEAK] EXPORT SDIO_IRQHandler [WEAK] EXPORT TIM5_IRQHandler [WEAK] EXPORT SPI3_IRQHandler [WEAK] EXPORT UART4_IRQHandler [WEAK] EXPORT UART5_IRQHandler [WEAK] EXPORT TIM6_IRQHandler [WEAK] EXPORT TIM7_IRQHandler [WEAK] EXPORT DMA2_Channel1_IRQHandler [WEAK] EXPORT DMA2_Channel2_IRQHandler [WEAK] EXPORT DMA2_Channel3_IRQHandler [WEAK] EXPORT DMA2_Channel4_5_IRQHandler [WEAK] WWDG_IRQHandler PVD_IRQHandler TAMPER_IRQHandler RTC_IRQHandler FLASH_IRQHandler RCC_IRQHandler EXTI0_IRQHandler EXTI1_IRQHandler EXTI2_IRQHandler EXTI3_IRQHandler EXTI4_IRQHandler DMA1_Channel1_IRQHandler DMA1_Channel2_IRQHandler DMA1_Channel3_IRQHandler DMA1_Channel4_IRQHandler DMA1_Channel5_IRQHandler DMA1_Channel6_IRQHandler DMA1_Channel7_IRQHandler ADC1_2_IRQHandler USB_HP_CAN1_TX_IRQHandler USB_LP_CAN1_RX0_IRQHandler CAN1_RX1_IRQHandler CAN1_SCE_IRQHandler EXTI9_5_IRQHandler TIM1_BRK_IRQHandler TIM1_UP_IRQHandler TIM1_TRG_COM_IRQHandler TIM1_CC_IRQHandler TIM2_IRQHandler TIM3_IRQHandler TIM4_IRQHandler I2C1_EV_IRQHandler I2C1_ER_IRQHandler I2C2_EV_IRQHandler I2C2_ER_IRQHandler SPI1_IRQHandler SPI2_IRQHandler USART1_IRQHandler USART2_IRQHandler USART3_IRQHandler EXTI15_10_IRQHandler RTCAlarm_IRQHandler USBWakeUp_IRQHandler TIM8_BRK_IRQHandler TIM8_UP_IRQHandler TIM8_TRG_COM_IRQHandler TIM8_CC_IRQHandler ADC3_IRQHandler FSMC_IRQHandler SDIO_IRQHandler TIM5_IRQHandler SPI3_IRQHandler UART4_IRQHandler UART5_IRQHandler TIM6_IRQHandler TIM7_IRQHandler DMA2_Channel1_IRQHandler DMA2_Channel2_IRQHandler DMA2_Channel3_IRQHandler DMA2_Channel4_5_IRQHandler B . ENDP ALIGN继续逐句分析
最新发布
08-03
<think>我们正在分析ARM汇编中的弱定义中断处理函数及其跳转行为。具体来说,用户提供的代码片段是: ```assembly NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP ``` 用户询问的是`EXPORT [WEAK]`和`B .`指令的作用分析。 ### 1. `EXPORT ... [WEAK]` 的作用 - `EXPORT` 伪指令用于声明一个全局符号,使得该符号可以被其他模块(文件)引用。 - `[WEAK]` 属性表示该符号为弱定义(weak symbol)。弱定义的含义是: - 如果在链接时在其他模块中找到了同名的强定义(非弱定义)符号,则链接器会使用强定义的符号。 - 如果没有找到其他定义,则使用这个弱定义符号。 - 在中断处理函数的上下文中,这种设计允许用户在其他文件中自定义中断处理函数。如果用户没有自定义,则使用这里默认的实现(即`B .`死循环)。 例如,用户可以在C语言文件中定义一个同名的函数: ```c void NMI_Handler(void) { // 用户自定义的不可屏蔽中断处理 } ``` 在链接时,这个C语言函数(强符号)会覆盖汇编中弱定义的`NMI_Handler`。 ### 2. `B .` 指令的作用 - `B .` 是一条分支(跳转)指令,其中`.`表示当前程序计数器(PC)的值。因此,`B .` 表示跳转到当前指令自身,形成无限循环。 - 这条指令的作用是让程序停在此处,不再继续执行。在中断处理函数中,这样做的目的是: - 当发生未被处理的中断时(即用户没有自定义该中断的处理函数),处理器会进入这个默认的中断处理函数。 - 通过死循环,程序会“卡死”在这里,这样可以防止程序跑飞,同时保留现场,便于调试器(如JTAG)介入分析问题。 ### 3. 整体行为分析 以`NMI_Handler`为例: 1. 当发生不可屏蔽中断(NMI)时,处理器会跳转到`NMI_Handler`的地址。 2. 如果用户没有自定义NMI处理函数,则执行默认的`B .`指令,进入死循环。 3. 如果用户自定义了NMI处理函数(强符号),则实际执行的是用户定义的函数。 ### 4. 设计意义 - **灵活性**:通过弱定义,芯片厂商提供的启动文件(通常包含这些默认的中断向量表和处理函数)允许用户灵活地覆盖任何中断处理函数。 - **安全性**:默认的死循环确保未处理的中断不会导致不可预知的行为(如执行随机代码),这在嵌入式系统的故障处理中非常重要。 ### 5. 与其他引用的关联 - 引用[1]中提到华大芯片对外设中断的接管,其原理类似:通过一个函数指针数组(`m_apfnIrqHandler`)来动态调用用户注册的中断处理函数。而这里是通过弱定义让用户直接覆盖中断处理函数。 - 引用[2]提到ARM汇编中`WEAK`关键字的灵活使用,正是我们这里讨论的弱定义机制。 - 引用[4]中提到的启动文件(如`startup_nrf52840.s`)的作用之一就是初始化中断向量表,其中包含这些弱定义的中断处理函数。 ### 相关问题 §§相关问题§§ 1. 在嵌入式系统中,为什么默认的中断处理函数通常设计为死循环(`B .`)?这种设计在调试和故障处理中有何优势? 2. 如何通过链接器脚本确保用户自定义的中断处理函数覆盖启动文件中的弱定义符号? 3. 在多任务操作系统中(如FreeRTOS),如何处理HardFault异常以定位引发异常的任务?与这里的默认处理方式有何不同?[^3]</think>### ARM汇编中弱定义中断处理函数及`B .`指令分析 #### 1. **`EXPORT [WEAK]`机制分析** ```assembly EXPORT NMI_Handler [WEAK] ``` - **弱定义属性**: - `[WEAK]`表示该符号为弱定义,允许用户在其它文件中定义同名强符号进行覆盖 - 若用户未自定义处理函数,则使用此默认实现 - 避免未定义中断导致的链接错误,增强代码健壮性[^2] - **工程应用场景**: ```c // 用户自定义覆盖示例(强符号) void HardFault_Handler(void) { log_error("HardFault at 0x%08X", SCB->HFSR); while(1); // 安全挂起 } ``` 链接时优先使用用户定义的强符号实现[^3] #### 2. **`B .`指令深度解析** ```assembly B . ; 跳转到当前地址 ``` - **机器码**:`0xE7FE`(Thumb指令集) - **物理行为**: - 形成无限循环:`PC ← PC + (0xFFFFFFFE << 1) + 4` - 实际效果:`PC = PC - 4`,持续执行当前指令 - **设计意义**: 1. **调试辅助** 保留异常现场寄存器(R0-R3, LR等),便于通过JTAG/SWD调试器分析异常原因 2. **安全防护** 防止未处理异常导致程序跑飞,符合IEC 61508功能安全标准 3. **资源管理** 避免异常传播消耗额外CPU资源,维持系统稳定状态[^1] #### 3. **完整异常处理流程** ```mermaid graph TD A[异常触发] --> B{用户是否定义处理程序?} B -->|是| C[执行用户自定义处理] B -->|否| D[执行默认 B . 死循环] D --> E[保留现场等待调试] ``` #### 4. **实际工程应用案例** 参考华大半导体实现(引用[1]): ```c void IRQ127_Handler(void) { m_apfnIrqHandler[INT127_IRQn](); // 动态调用注册函数 __DSB(); // 数据同步屏障 } ``` - **对比分析**: - 相同点:都使用弱定义机制允许覆盖 - 不同点: - 华大方案:通过函数指针实现动态注册 - 本方案:直接使用汇编级弱定义 - 性能差异:函数指针方案增加1次跳转,但扩展性更优[^1] ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值