在GCC中使用"naked"属性来执行函数

Art*_*sky 10 attributes gcc

GCC文档声明在6.30声明函数属性:

naked

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

我可以使用裸函数中的C语法安全地调用函数,还是仅使用asm?

dav*_*vid 6

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

请注意,断言您可以在裸函数中"安全地"使用汇编语言有点无稽之谈.您对使用汇编语言执行的任何操作负有全部责任,因为您对"安全"功能进行的任何调用都是如此.

为了确保您的通用被调用函数不是静态的或内联的,它应该在一个单独的编译单元中.

"裸体"功能不包括任何序言或结语 - 他们是赤裸裸的.特别是,它们不包括堆栈上的局部变量操作,保存或恢复寄存器,或返回调用函数.

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

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

这导致了下一点:您需要序言和结语才能封装被调用函数的操作.如果被调用的函数也是安全的(没有显式或隐式的局部变量,也没有对状态寄存器的更改),它可以安全地静态和/或内联.与asm一样,您有责任确保这是真的.


Ale*_*min 5

如果你在naked函数中唯一做的就是调用另一个函数,你可以只使用一个JMP机器码指令.

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

  • 这个答案是不正确的.只要您实施ABI,您就可以在裸体功能中执行任何操作,只要您实施ABI - 这意味着您必须知道,理解并能够可靠地预测正在使用的ABI.此外,文档是不正确的,因为您可以安全地从asm语句中访问全局变量而不会产生不良副作用,但如果您这样做,则应该在clobbers中放入"memory". (3认同)
  • 我问了我的问题,因为在 AVR 的 FreeRTOS 源中,我看到了以下内容 无效 vPortYield( void ) { portSAVE_CONTEXT(); vTaskSwitchContext(); portRESTORE_CONTEXT(); asm volatile ("ret"); portSAVE_CONTEXT() 和 portRESTORE_CONTEXT() 是带有 asm 的宏,但 vTaskSwitchContext 是一个函数。 (2认同)