了解 ARM Cortex-M 中断向量 table 定义的 C 语法
Understanding this C syntax for ARM Cortex-M interrupt vector table definition
我目前正在查看其他人为 ARM Cortex-M 微控制器编写的一些启动代码。可以在 Github repo.
中找到整个文件
它会做一些事情,比如设置堆栈指针和初始化 .data
和 .bss
部分,适当地使用一些简单的 for 循环。
我很难理解用于定义中断向量的语法table:
#define DUMMY __attribute__ ((weak, alias ("irq_handler_dummy")))
//-----------------------------------------------------------------------------
void irq_handler_reset(void);
DUMMY void irq_handler_nmi(void);
DUMMY void irq_handler_hard_fault(void);
// etc.
extern int main(void);
extern void _stack_top(void);
// etc.
//-----------------------------------------------------------------------------
__attribute__ ((used, section(".vectors")))
void (* const vectors[])(void) =
{
&_stack_top, // 0 - Initial Stack Pointer Value
// Cortex-M0+ handlers
irq_handler_reset, // 1 - Reset
irq_handler_nmi, // 2 - NMI
irq_handler_hard_fault, // 3 - Hard Fault
// etc.
};
GCC 的 __attribute__
定义很清楚,我在官方文档中找到了它的作用的答案:GCC Function attributes.
我仍然不知道如何解析和表达这个语法的含义
void (* const vectors[])(void)
谁能帮我理解所有这些语法解包或表示什么?
vectors
是一个 const 函数指针数组,它接受 return void
.
_stack_top
不是函数指针,它是堆栈顶部的地址,但对于皮质 m,它始终是向量 table 中的第一个元素。
Cortex M 架构和您正在使用的它的实现定义了向量的顺序和位置 table。此代码是生成 table 并将其放置在正确位置的语法糖。
void (* const vectors[])(void)
它是 const 函数指针数组 引用函数的定义和声明,该函数不带任何参数且 return 没有任何值。
它是通过引用源代码中定义的中断处理程序(函数)进行初始化的。第一个值采用链接描述文件中定义的符号 _stack_top
的地址。该值将在微启动时设置初始堆栈指针。
具有 weak
链接的函数可以被其他函数替换,而不会产生链接器错误。
向量table本质上只是一个ISR地址数组。其中翻译成C可以看作是一个函数指针数组。创建向量 table 作为函数指针数组是很常见的。
Cortex M 之所以成为一个特殊的雪花,是因为它通过硬件从闪存加载堆栈指针,而不是程序员在 运行 时间内手动设置它。向量的第一项 table 包含初始堆栈指针的值 - 它实际上 而不是 函数地址。因此,某种破解方式是必要的。 _stack_top
可能会归结为链接描述文件中设置的某个堆栈地址。您的代码永远不会直接使用此项,它就在那里,以便在启动时正确设置堆栈。
除了那个,其余的只是指向中断服务程序的普通函数指针。由于 ISR 不带参数且 returns 赋值,因此 ISR 函数指针的语法为:
void (*name) (void)
这样的函数指针数组声明为:
void (*name [n]) (void)
其中 n
可以选择性地用于表示数组大小。
__attribute__ ((used, section(".vectors")))
只是将数组放在特定地址,在本例中是从 0 开始。您可以检查链接描述文件,您会在那里找到 .vectors
。
我们希望这个向量 table 作为只读数据加载到闪存 ROM 中。因此我们希望指针是只读的,而不是它们指向的内容。这是通过将 const
放在 *
的右侧来实现的(同样的规则也适用于普通对象指针):
void (*const vectors[])(void)
如果使用 typedef
,我们可以写出更具可读性的代码:
typedef void isr_vector_t (void);
...
isr_vector_t* const vectors[] = { ... };
vectors -- vectors
vectors[] -- is an array of
* const vectors[] -- const pointer to
(* const vectors[])( ) -- function taking
(* const vectors[])(void) -- no parameters
void (* const vectors[])(void) -- returning void
IOW,每个vectors[i]
都是一个指向函数的指针;指向的函数在初始化程序中指定:
vectors[1] == irq_handler_reset, // 1 - Reset
vectors[2] == irq_handler_nmi, // 2 - NMI
vectprs[3] == irq_handler_hard_fault, // 3 - Hard Fault
*
后面的const
表示vector[i]
初始化后不能更新; IOW,您不能将 vectors[1]
设置为指向 irq_handler_reset
以外的函数。
const T *p; // you can update p to point to different objects, but
// you cannot write to the pointed-to objects
T const *p; // same as above
T * const p = some_addr; // you can write a new value to the object at
// some_addr, but you can't write a new value
// to p.
我目前正在查看其他人为 ARM Cortex-M 微控制器编写的一些启动代码。可以在 Github repo.
中找到整个文件它会做一些事情,比如设置堆栈指针和初始化 .data
和 .bss
部分,适当地使用一些简单的 for 循环。
我很难理解用于定义中断向量的语法table:
#define DUMMY __attribute__ ((weak, alias ("irq_handler_dummy")))
//-----------------------------------------------------------------------------
void irq_handler_reset(void);
DUMMY void irq_handler_nmi(void);
DUMMY void irq_handler_hard_fault(void);
// etc.
extern int main(void);
extern void _stack_top(void);
// etc.
//-----------------------------------------------------------------------------
__attribute__ ((used, section(".vectors")))
void (* const vectors[])(void) =
{
&_stack_top, // 0 - Initial Stack Pointer Value
// Cortex-M0+ handlers
irq_handler_reset, // 1 - Reset
irq_handler_nmi, // 2 - NMI
irq_handler_hard_fault, // 3 - Hard Fault
// etc.
};
GCC 的 __attribute__
定义很清楚,我在官方文档中找到了它的作用的答案:GCC Function attributes.
我仍然不知道如何解析和表达这个语法的含义
void (* const vectors[])(void)
谁能帮我理解所有这些语法解包或表示什么?
vectors
是一个 const 函数指针数组,它接受 return void
.
_stack_top
不是函数指针,它是堆栈顶部的地址,但对于皮质 m,它始终是向量 table 中的第一个元素。
Cortex M 架构和您正在使用的它的实现定义了向量的顺序和位置 table。此代码是生成 table 并将其放置在正确位置的语法糖。
void (* const vectors[])(void)
它是 const 函数指针数组 引用函数的定义和声明,该函数不带任何参数且 return 没有任何值。
它是通过引用源代码中定义的中断处理程序(函数)进行初始化的。第一个值采用链接描述文件中定义的符号 _stack_top
的地址。该值将在微启动时设置初始堆栈指针。
具有 weak
链接的函数可以被其他函数替换,而不会产生链接器错误。
向量table本质上只是一个ISR地址数组。其中翻译成C可以看作是一个函数指针数组。创建向量 table 作为函数指针数组是很常见的。
Cortex M 之所以成为一个特殊的雪花,是因为它通过硬件从闪存加载堆栈指针,而不是程序员在 运行 时间内手动设置它。向量的第一项 table 包含初始堆栈指针的值 - 它实际上 而不是 函数地址。因此,某种破解方式是必要的。 _stack_top
可能会归结为链接描述文件中设置的某个堆栈地址。您的代码永远不会直接使用此项,它就在那里,以便在启动时正确设置堆栈。
除了那个,其余的只是指向中断服务程序的普通函数指针。由于 ISR 不带参数且 returns 赋值,因此 ISR 函数指针的语法为:
void (*name) (void)
这样的函数指针数组声明为:
void (*name [n]) (void)
其中 n
可以选择性地用于表示数组大小。
__attribute__ ((used, section(".vectors")))
只是将数组放在特定地址,在本例中是从 0 开始。您可以检查链接描述文件,您会在那里找到 .vectors
。
我们希望这个向量 table 作为只读数据加载到闪存 ROM 中。因此我们希望指针是只读的,而不是它们指向的内容。这是通过将 const
放在 *
的右侧来实现的(同样的规则也适用于普通对象指针):
void (*const vectors[])(void)
如果使用 typedef
,我们可以写出更具可读性的代码:
typedef void isr_vector_t (void);
...
isr_vector_t* const vectors[] = { ... };
vectors -- vectors
vectors[] -- is an array of
* const vectors[] -- const pointer to
(* const vectors[])( ) -- function taking
(* const vectors[])(void) -- no parameters
void (* const vectors[])(void) -- returning void
IOW,每个vectors[i]
都是一个指向函数的指针;指向的函数在初始化程序中指定:
vectors[1] == irq_handler_reset, // 1 - Reset
vectors[2] == irq_handler_nmi, // 2 - NMI
vectprs[3] == irq_handler_hard_fault, // 3 - Hard Fault
*
后面的const
表示vector[i]
初始化后不能更新; IOW,您不能将 vectors[1]
设置为指向 irq_handler_reset
以外的函数。
const T *p; // you can update p to point to different objects, but
// you cannot write to the pointed-to objects
T const *p; // same as above
T * const p = some_addr; // you can write a new value to the object at
// some_addr, but you can't write a new value
// to p.