首页 > 解决方案 > 在裸函数内部 - 如何进行简单的赋值

问题描述

这是已经存在并有效的功能的开始;注释行是我的补充,其目的是切换一个别针。

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函数有关,但我不明白为什么简单的赋值会导致问题。

两个问题:

  1. 为什么这条线会触发硬故障?
  2. 如何在此函数中执行此分配?

标签: c++gccassemblyinline-assembly

解决方案


幸运的是,您以前版本的函数碰巧可以正常工作而不会崩溃。

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

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

如果你想从一个裸函数运行 C++ 代码,你可以call使用一个常规函数(或bl在 ARM、jalMIPS 等上),遵循标准调用约定。


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

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

你确定这个功能需要naked吗?我想那是因为你操纵lr返回到新的上下文。

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


推荐阅读