在裸函数内部 - 如何进行简单的赋值

Posted

技术标签:

【中文标题】在裸函数内部 - 如何进行简单的赋值【英文标题】:inside naked function - how to do simple assignment 【发布时间】:2019-01-19 00:34:44 【问题描述】:

这是一个已经存在并且可以工作的函数的开始;注释行是我的补充,它的目的是切换一个别针。

inline __attribute__((naked)) 
void CScheduler::SwapToThread(void* pNew, void* pPrev)
   
    //*(volatile DWORD*)0x400FF08C = (1 << 14);
    if (pPrev != NULL)
    
        if (pPrev == this) // Special case to save scheduler stack on startup
        
            asm("mov lr,%0"::"p"(&CScheduler_Run_Exit));     // load r1 with schedulers End thread
            asm("orr lr, 1");

当我取消注释我的添加时,我的硬故障处理程序将执行。我知道这与 naked 函数有关,但我不明白为什么简单的分配会导致问题。

两个问题:

    为什么这条线会触发硬故障? 如何在这个函数中执行这个赋值?

【问题讨论】:

我不认为你的多个 asm 应该像那样不相交。 您是否绝对肯定您的程序拥有地址 0x400FF08C?明天,后天,后天?这看起来很脆弱。 这看起来很脆弱......你可以在一个裸函数中可靠地做的唯一事情就是使用内联汇编,句号。即使是已经存在的分支也不能保证完全正常工作。如果你想写 C++ 做一个非裸函数。如果您需要在那里做那件事,请在组装中进行。 我知道你不想听到这个,但docs 在这一点上真的很清楚:使用扩展 asm 或基本混合asm 和 C 代码似乎可以工作,但它们不能可靠地工作并且不受支持。 也就是说,您的 RTOS 是否支持 2 个线程同时写入同一地址?这里没有任何保护措施可以避免它。您可以将内存写入移动到其他地方并让它工作吗?您的操作系统不使用保护模式,是吗?调度程序在调用它之前是否禁用了某些东西? 裸函数不会自动包含函数序言/结语。您必须在编写纯汇编之前和之后设置堆栈和寄存器。 【参考方案1】:

你以前版本的函数碰巧可以正常工作而没有崩溃,这只是运气。

唯一可以安全地放在naked 函数中的是纯Basic Asm 语句。 https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html。您可以将其拆分为多个 Basic Asm 语句,而不是 asm("insn \n\t"/"insn2 \n\t"/...);,但您必须自己在 asm 中编写整个函数。

虽然使用扩展 asm 或混合使用基本 asm 和 C 代码似乎可以工作,但不能依赖它们可靠地工作并且不受支持。

如果您想从一个裸函数运行 C++ 代码,您可以按照标准调用约定 call 一个常规函数(或 ARM 上的 bl、MIPS 上的 jal 等)。


至于本案的具体原因?也许在寄存器中创建该地址会踩在函数 args 上,导致分支出错?如果需要,请检查生成的 asm,但它 100% 不受支持。

或者它最终使用了更多的寄存器,因为它是naked 没有正确保存/恢复调用保留的寄存器?我自己没有看过代码生成的裸函数。

你确定这个函数需要naked吗?我猜那是因为您操纵 lr 以返回到新上下文。

如果你不想在 asm 中写更多的逻辑,也许让这个函数的调用者做更多的工作(也许传递指针和/或布尔参数更简单地告诉它需要做什么,所以你的输入是已经在寄存器中,并且您不需要访问全局变量。

【讨论】:

以上是关于在裸函数内部 - 如何进行简单的赋值的主要内容,如果未能解决你的问题,请参考以下文章

第十三章 高级指针话题指针

如何修改全局变量的值

函数内部的C指针赋值

C++要点总结

箭头函数 解构赋值 立即执行函数 (function() )()

Python函数中的参数