使用为函数指针声明指定的“__irq”有什么作用吗?
Does using the `__irq` specified for a function pointer declaration do anything?
我必须为一个项目做一些嵌入式编程,并且正在通过查看其他一些项目来学习。我发现以下代码声明了向量 table:
typedef void (*const vect_t)(void) __irq;
vect_t vector_table[]
__attribute__ ((section("vectors"))) = {
(vect_t) (RAM_BASE + RAM_SIZE),
(vect_t) Reset_Handler,
// ...
};
重置处理程序声明如下:
void Reset_Handler(void) {
// ... no interesting
}
我阅读了 __irq
,ARM 编译器文档说明如下:
The compiler generates function entry and exit sequences suitable for
use in an interrupt handler when this attribute is present.
我猜 vect_t
应该是指向 void
函数的指针,它不带任何参数,即 suitable 用作中断处理程序。这对我来说似乎很奇怪,因为 __irq
应该只是实现的编译器提示,而不是对函数类型有贡献的东西(比如参数或 return type do)。
我的假设是 __irq
应该用在 Reset_Handler
(以及所有其他中断处理程序)上,而不是在类型定义中。这是正确的吗?
请注意,我不是在问 __irq
做什么。我知道这不是 C 标准的一部分,而是 ARM 编译器扩展。我也明白使用它时产生的代码取决于CPU架构。
一般来说,中断服务例程 (ISR) 使用不同的指令进行 returning。普通函数只使用“return from subroutine”指令,该指令根据调用约定弹出堆栈。然而,ISR 不是由程序调用,而是由硬件调用,因此它们通常具有不同的调用约定。为了正确生成这些特殊指令,你需要一些非标准的中断语法。
该代码是一个中断向量table,所以类型定义是正确的。但是,如果 ISR 被声明为没有任何特殊关键字 void Reset_Handler(void)
的普通函数,那么这将不起作用。此处不正确的转换 (vect_t) Reset_Handler
将确保在中断时调用此函数,但它不会 return 从该函数正确地调用 - 可能会崩溃。
My assumption is that __irq should have been used on Reset_Handler (and on all other interrupt handlers) and not in the type definition. Is this correct?
它应该在向量 table 和 ISR 函数定义中。
例如使用 gcc(attributes/directives/pragmas 等特定于工具而不是 C 语言)
struct interrupt_frame;
__attribute__ ((interrupt))
void x (struct interrupt_frame *frame)
{
}
void y ( void )
{
}
使用通用的 aarch32 类型 arm 目标:
Disassembly of section .text:
00000000 <x>:
0: e25ef004 subs pc, lr, #4
00000004 <y>:
4: e12fff1e bx lr
现在让我们进一步复杂化
struct interrupt_frame;
unsigned int k;
__attribute__ ((interrupt))
void x (struct interrupt_frame *frame)
{
k=5;
}
void y ( void )
{
k=5;
}
00000000 <x>:
0: e92d000c push {r2, r3}
4: e3a02005 mov r2, #5
8: e59f3008 ldr r3, [pc, #8] ; 18 <x+0x18>
c: e5832000 str r2, [r3]
10: e8bd000c pop {r2, r3}
14: e25ef004 subs pc, lr, #4
0000001c <y>:
1c: e3a02005 mov r2, #5
20: e59f3004 ldr r3, [pc, #4] ; 2c <y+0x10>
24: e5832000 str r2, [r3]
28: e12fff1e bx lr
对于中断,您需要保留中断中的所有寄存器,对于常规函数,调用约定规定了函数中哪些寄存器是可变的。因此,通过此示例,您可以看到该指令的主要原因,保留状态并使用中断指令中的特定 return。
因为 cortex-m 架构(armv6-m、7-m 和 8-m)的设计使您可以将 C 函数直接放在向量中 table,而不用任何 asm 环绕它们(硬件负责保存状态和特殊的 return 问题)。编译器以相同的方式生成代码,基本上该属性对该目标没有影响:
00000000 <x>:
0: 2205 movs r2, #5
2: 4b01 ldr r3, [pc, #4] ; (8 <x+0x8>)
4: 601a str r2, [r3, #0]
6: 4770 bx lr
0000000c <y>:
c: 2205 movs r2, #5
e: 4b01 ldr r3, [pc, #4] ; (14 <y+0x8>)
10: 601a str r2, [r3, #0]
12: 4770 bx lr
最后要注意的是,您不会 return 来自重置向量,因此 cortex-m 没有理由为重置向量使用这样的 attribute/directive。好吧,如果它确实是一个裸机向量 table,那么你不应该从重置向量中 return 架构(与使用相同的方案用于位于 os 上的一般应用程序入口相比,不是裸机-metal)(或调用此代码的引导加载程序,您当然可以return)。
其他架构不倾向于将重置集中在“中断”或“异常”列表中重置重置,ARM 文档和代码倾向于将它们视为任何其他异常,因此您仍然必须考虑它的不同。
我必须为一个项目做一些嵌入式编程,并且正在通过查看其他一些项目来学习。我发现以下代码声明了向量 table:
typedef void (*const vect_t)(void) __irq;
vect_t vector_table[]
__attribute__ ((section("vectors"))) = {
(vect_t) (RAM_BASE + RAM_SIZE),
(vect_t) Reset_Handler,
// ...
};
重置处理程序声明如下:
void Reset_Handler(void) {
// ... no interesting
}
我阅读了 __irq
,ARM 编译器文档说明如下:
The compiler generates function entry and exit sequences suitable for use in an interrupt handler when this attribute is present.
我猜 vect_t
应该是指向 void
函数的指针,它不带任何参数,即 suitable 用作中断处理程序。这对我来说似乎很奇怪,因为 __irq
应该只是实现的编译器提示,而不是对函数类型有贡献的东西(比如参数或 return type do)。
我的假设是 __irq
应该用在 Reset_Handler
(以及所有其他中断处理程序)上,而不是在类型定义中。这是正确的吗?
请注意,我不是在问 __irq
做什么。我知道这不是 C 标准的一部分,而是 ARM 编译器扩展。我也明白使用它时产生的代码取决于CPU架构。
一般来说,中断服务例程 (ISR) 使用不同的指令进行 returning。普通函数只使用“return from subroutine”指令,该指令根据调用约定弹出堆栈。然而,ISR 不是由程序调用,而是由硬件调用,因此它们通常具有不同的调用约定。为了正确生成这些特殊指令,你需要一些非标准的中断语法。
该代码是一个中断向量table,所以类型定义是正确的。但是,如果 ISR 被声明为没有任何特殊关键字 void Reset_Handler(void)
的普通函数,那么这将不起作用。此处不正确的转换 (vect_t) Reset_Handler
将确保在中断时调用此函数,但它不会 return 从该函数正确地调用 - 可能会崩溃。
My assumption is that __irq should have been used on Reset_Handler (and on all other interrupt handlers) and not in the type definition. Is this correct?
它应该在向量 table 和 ISR 函数定义中。
例如使用 gcc(attributes/directives/pragmas 等特定于工具而不是 C 语言)
struct interrupt_frame;
__attribute__ ((interrupt))
void x (struct interrupt_frame *frame)
{
}
void y ( void )
{
}
使用通用的 aarch32 类型 arm 目标:
Disassembly of section .text:
00000000 <x>:
0: e25ef004 subs pc, lr, #4
00000004 <y>:
4: e12fff1e bx lr
现在让我们进一步复杂化
struct interrupt_frame;
unsigned int k;
__attribute__ ((interrupt))
void x (struct interrupt_frame *frame)
{
k=5;
}
void y ( void )
{
k=5;
}
00000000 <x>:
0: e92d000c push {r2, r3}
4: e3a02005 mov r2, #5
8: e59f3008 ldr r3, [pc, #8] ; 18 <x+0x18>
c: e5832000 str r2, [r3]
10: e8bd000c pop {r2, r3}
14: e25ef004 subs pc, lr, #4
0000001c <y>:
1c: e3a02005 mov r2, #5
20: e59f3004 ldr r3, [pc, #4] ; 2c <y+0x10>
24: e5832000 str r2, [r3]
28: e12fff1e bx lr
对于中断,您需要保留中断中的所有寄存器,对于常规函数,调用约定规定了函数中哪些寄存器是可变的。因此,通过此示例,您可以看到该指令的主要原因,保留状态并使用中断指令中的特定 return。
因为 cortex-m 架构(armv6-m、7-m 和 8-m)的设计使您可以将 C 函数直接放在向量中 table,而不用任何 asm 环绕它们(硬件负责保存状态和特殊的 return 问题)。编译器以相同的方式生成代码,基本上该属性对该目标没有影响:
00000000 <x>:
0: 2205 movs r2, #5
2: 4b01 ldr r3, [pc, #4] ; (8 <x+0x8>)
4: 601a str r2, [r3, #0]
6: 4770 bx lr
0000000c <y>:
c: 2205 movs r2, #5
e: 4b01 ldr r3, [pc, #4] ; (14 <y+0x8>)
10: 601a str r2, [r3, #0]
12: 4770 bx lr
最后要注意的是,您不会 return 来自重置向量,因此 cortex-m 没有理由为重置向量使用这样的 attribute/directive。好吧,如果它确实是一个裸机向量 table,那么你不应该从重置向量中 return 架构(与使用相同的方案用于位于 os 上的一般应用程序入口相比,不是裸机-metal)(或调用此代码的引导加载程序,您当然可以return)。
其他架构不倾向于将重置集中在“中断”或“异常”列表中重置重置,ARM 文档和代码倾向于将它们视为任何其他异常,因此您仍然必须考虑它的不同。