使用;裸体的;GCC中函数的属性

使用;裸体的;GCC中函数的属性,gcc,attributes,Gcc,Attributes,GCC文件规定: 裸体 在ARM、AVR、IP2K、RX和SPU端口上使用此属性可指示指定的函数不需要编译器生成的序言/尾声序列。由程序员提供这些序列。裸函数中可以安全包含的唯一语句是没有操作数的asm语句。应避免使用所有其他语句,包括局部变量声明、if语句等。裸函数应用于实现汇编函数的主体,同时允许编译器为汇编程序构造必需的函数声明 我可以从裸函数中使用C语法安全地调用函数,还是只能使用asm 裸函数中唯一可以安全包含的语句是没有操作数的asm语句。应避免使用所有其他语句,包括局部变量声明、i

GCC文件规定:

裸体

在ARM、AVR、IP2K、RX和SPU端口上使用此属性可指示指定的函数不需要编译器生成的序言/尾声序列。由程序员提供这些序列。裸函数中可以安全包含的唯一语句是没有操作数的
asm
语句。应避免使用所有其他语句,包括局部变量声明、
if
语句等。裸函数应用于实现汇编函数的主体,同时允许编译器为汇编程序构造必需的函数声明

我可以从裸函数中使用C语法安全地调用函数,还是只能使用asm

裸函数中唯一可以安全包含的语句是没有操作数的asm语句。应避免使用所有其他语句,包括局部变量声明、if语句等


根据您已经给出的描述,我假设即使函数调用也不适合“裸”关键字。

如果裸函数中唯一要做的事情是调用另一个函数,那么您可以只使用一条JMP机器代码指令


跳转到的函数将有一个有效的序言,它应该直接返回到裸函数的调用方,因为JMP不会在堆栈上推送返回地址。

如果被调用的函数有完整的序言和尾声,您可以安全地从裸函数调用函数

请注意,断言您可以在裸函数中“安全地”使用汇编语言有点胡说八道。您完全负责使用汇编语言所做的任何事情,就像您对“安全”函数所做的任何调用一样

为了确保泛型调用函数不是静态的或内联的,它应该位于单独的编译单元中

“裸体”函数不包括任何开场白或尾声——它们是裸体的。特别是,它们不包括本地变量堆栈上的操作、保存或恢复寄存器或返回调用函数的操作

这并不意味着不存在堆栈——堆栈是在程序初始化中初始化的,而不是在任何函数初始化中初始化的。由于堆栈存在,所以调用的函数序言和尾声工作正常。函数调用可以安全地推送它的返回地址、使用的任何寄存器以及任何局部变量的空间。返回时(使用返回地址),寄存器被恢复,堆栈空间被释放

静态或内联函数可能没有完整的序言和尾声。它们可以而且可能依赖于调用函数来管理堆栈和恢复损坏的寄存器


这就引出了下一点:您只需要序言和尾声来封装被调用函数的操作。如果被调用的函数也是安全的(没有显式或隐式局部变量,状态寄存器没有更改),那么它可以是安全的静态和/或内联的。与asm一样,您有责任确保这是真实的。

我问了我的问题,因为在AVR的FreeRTOS源代码中,我看到了以下void vPortYield(void)属性((裸体));void vPortYield(void){portSAVE_CONTEXT();vTaskSwitchContext();portRESTORE_CONTEXT();asm volatile(“ret”);}portSAVE_CONTEXT()和portRESTORE_CONTEXT()是asm的宏,但vTaskSwitchContext是一个函数。此答案不正确。你可以在一个裸函数中做任何事情,只要你实现了ABI,你就可以在任何地方做任何事情——这意味着你必须知道、理解并能够可靠地预测正在使用的ABI。另外,文档是不正确的,因为您可以从asm语句中安全地访问全局变量,而不会产生不良的副作用,但是如果这样做,您应该将“内存”放在缓冲区中。