gcc扩展选项__attribute__((interrupt))——指定中断处理函数属性

1、调用者保存寄存器与被调用者保存寄存器

  • 假设:函数A调用了函数B,寄存器x在函数B中被修改了,对于A函数而言,逻辑上x内容在调用函数B的前后应该保持一致。现在需要解决前后不一致的问题,有两种思路:
    • 第一种:调用者保存的寄存器
      • 在函数A在调用函数B之前提前把寄存器x的值存入栈中,执行完函数B之后再恢复x的内容。
      • 在函数跳转前保存的寄存器,叫调用者保存寄存器
    • 第二种:被调用者保存的寄存器
      • 函数B在使用寄存器x前,先保存寄存器x的值到栈中,在函数B返回之前,要恢复寄存器x原来存储
        的内容
      • 在函数中,使用前必须保存、返回前必须恢复的寄存器
  • 至于怎么划分寄存器是调用者保存,还是被调用者保存,这是芯片架构的函数调用规范决定的,写C语言的程序员不用感知。想了解RISC-V架构的函数调用规范,可参考文章:《RISC-V架构的函数调用规范和栈布局》

2、异常向量表的访问方式:direct mode、vector mode

3、attribute((interrupt))的作用

c 复制代码
__attribute__((interrupt)) void my_interrupt_function(void)
{
	...... //中断处理
	return;
}
  • 在使用中断的vector模式时,需要将中断处理函数写到对应的异常向量表处,当产生中断时,硬件将自动跳转
  • 中断处理就涉及到中断现场的保存和恢复,vector模式的中断处理函数一般C语言写的,那是否需要在中断处理函数里去写保存/恢复中断现场的代码?答案是不需要,只需要再中断处理函数前使用"attribute((interrupt))"修饰
  • 作用:编译器将C语言写的中断处理函数翻译成汇编代码时,会自动插入保存/恢复现场的汇编代码。也就是把中断处理函数中会用到的寄存器都先存入栈中,在中断返回前,再从栈里面读出来恢复到寄存器中

4、汇编代码分析

  • 同样的C语言函数,对比使用/不使用__attribute__((interrupt))修饰得到的反汇编文件
  • 可以看到,使用__attribute__((interrupt))修饰后,汇编代码会多申请栈空间用于保存/恢复现场

5、总结

  • 不使用__attribute__((interrupt))修饰,函数内只需要保存被调用者保存的寄存器
  • 使用__attribute__((interrupt))修饰后,只要在函数内使用到的寄存器都必须保存再恢复,会占用更多的栈空间,翻译得到的汇编代码也会增多
  • 还可以指定中断处理函数的优化等级: __attribute__((interrupt, optimize("O0")))
  • 总结:只有中断处理函数才用__attribute__((interrupt))修饰,其余常规函数不要使用
相关推荐
百里杨4 个月前
RISC-V特权架构 - 时钟中断处理
risc-v·委托·注入·中断处理
黑不溜秋的5 个月前
驱动开发系列-中断处理
驱动·中断处理
charlie1145141918 个月前
Linux内核深入学习 - 中断与异常(上)
linux·操作系统·c·中断处理