【问题标题】:C: Return general purpose registerC:返回通用寄存器
【发布时间】:2020-06-20 03:59:03
【问题描述】:

我有以下功能可以进行主管调用。

inline uint32_t os_SVC(uint32_t n, uint32_t pid, void* ptr1, void (*ptr2)()){
  __asm("svc #0");
  return;
}

通过在 SVC ISR 期间更改堆栈,我知道 R0 将包含来自 SVC ISR 的返回参数。据我了解,这就是 AAPCS 从函数返回值的方式。但是如何从os_SVC 返回 R0 寄存器?目前它给了我一个警告,因为我正在从函数返回而没有提供返回值。

【问题讨论】:

标签: c arm embedded


【解决方案1】:

您的编译器可能有进一步的扩展,允许您将数据传入和传出程序集插入。您没有告诉我们您使用的是哪个编译器,所以我将向您展示如何使用 GCC 来完成它,我记得没有查找它的扩展:

uint32_t os_SVC(uint32_t n, uint32_t pid, void *p1, void (*p2)(void))
{
    register uint32_t rv asm ("r0");
    asm ("svc #0" : "=r" (rv))
    return rv;
}

rv 声明上的 register ... asm ("r0") 注释要求编译器将其放入 r0,而 asm 语句上的 : "=r" (rv) 注释告诉它汇编指令写入该变量。然后你就可以正常返回rv了。

另外,请注意我是如何删除inline 的?那是故意的。如果你内联这个函数,参数将不会整齐地排列在系统调用期望找到它们的堆栈上。如果您的操作系统需要寄存器中的系统调用参数,您可以进一步注释程序集插入并进行内联工作,但如果它希望它们在堆栈中,则让函数脱机是最好的方法。 (在生产代码中,我会将__attribute__((noinline)) 放在函数本身上,并将__attribute__((used)) 放在它的每个参数上,但是对于示例来说,这太混乱了。)

我正在使用的扩展的文档位于 GCC 手册的 "Using Assembly Language with C" 部分。仔细阅读全文

如果您不使用 GCC,请查阅您的编译器手册以查看它是否具有等效扩展。如果它没有等效的扩展,您唯一的选择可能是完全用汇编语言编写这个函数,在一个单独的.S 文件中。

【讨论】:

  • 非常感谢您的回答,并警告我有关内联!我确实在使用 arm gcc 编译器。当您说“asm 语句上的: "=r" (rv) 注释告诉它汇编指令写入该变量”时,是否需要指令本身写入寄存器?或者在 ISR 触发结束后,寄存器值已经改变(由于在返回时从堆栈中弹出编辑值而改变)就足够了吗?
  • @MHilton 在控制到达第一条指令svc之后,值已经改变就足够了。
  • 您可能想查看生成的机器代码。为此,您可以使用选项-S-o output_file.s 调用GCC 来查看此内容,或者使用objdump 来反汇编目标文件。还有一些选项可以传递给组装通道以创建列表。
猜你喜欢
  • 2011-07-18
  • 1970-01-01
  • 2017-09-19
  • 2011-05-24
  • 2013-08-14
  • 2013-09-28
  • 2014-11-19
  • 2011-04-18
相关资源
最近更新 更多