在裸函数内部 - 如何进行简单的赋值
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 中写更多的逻辑,也许让这个函数的调用者做更多的工作(也许传递指针和/或布尔参数更简单地告诉它需要做什么,所以你的输入是已经在寄存器中,并且您不需要访问全局变量。
【讨论】:
以上是关于在裸函数内部 - 如何进行简单的赋值的主要内容,如果未能解决你的问题,请参考以下文章