首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用GCC内联程序集和采用即时值的指令

使用GCC内联程序集和采用即时值的指令
EN

Stack Overflow用户
提问于 2012-07-07 18:08:56
回答 4查看 9.3K关注 0票数 11

问题所在

我正在为ARM Cortex-M3处理器开发一个自定义操作系统。要与内核交互,用户线程必须生成一个SuperVisor调用(SVC)指令(以前称为SoftWare中断)。ARM中这一指令的定义是:

这意味着指令需要立即参数,而不是寄存器值。

这使得我很难以一种可读的方式设计我的界面。它需要如下代码:

代码语言:javascript
复制
asm volatile( "svc #0");

当我更喜欢这样的东西

代码语言:javascript
复制
svc(SVC_YIELD);

但是,我不知道如何构造这个函数,因为SVC指令需要一个直接的参数,而且当值通过寄存器传入时,我不能提供这个参数。

内核:

对于背景,svc指令在内核中被解码如下

代码语言:javascript
复制
#define SVC_YIELD   0
// Other SVC codes

// Called by the SVC interrupt handler (not shown)
void handleSVC(char code)
{
  switch (code) {

    case SVC_YIELD:
      svc_yield();
      break;
    // Other cases follow

这个案例陈述正在迅速失控,但我看不出有什么办法可以解决这个问题。欢迎任何建议。

我试过的

带有寄存器参数的SVC

我一开始考虑

代码语言:javascript
复制
__attribute__((naked)) svc(char code)
{
    asm volatile ("scv r0"); 
}

但是,这当然不起作用,因为SVC需要注册参数。

蛮力

试图解决这一问题的暴力行动看上去像是:

代码语言:javascript
复制
void svc(char code)
  switch (code) {
    case 0:
      asm volatile("svc #0");
      break;
    case 1:
      asm volatile("svc #1");
      break;
    /* 253 cases omitted */
    case 255:
      asm volatile("svc #255");
      break;
  }
}

但那有一种讨厌的代码气味。当然,这一点可以做得更好。

动态生成指令编码

最后一次尝试是在RAM中生成指令(其余代码是从只读Flash运行的),然后运行它:

代码语言:javascript
复制
void svc(char code)
{
  asm volatile (
      "orr r0, 0xDF00  \n\t" // Bitwise-OR the code with the SVC encoding
      "push {r1, r0}   \n\t" // Store the instruction to RAM (on the stack)
      "mov r0, sp      \n\t" // Copy the stack pointer to an ordinary register
      "add r0, #1      \n\t" // Add 1 to the address to specify THUMB mode
      "bx r0           \n\t" // Branch to newly created instruction
      "pop {r1, r0}    \n\t" // Restore the stack
      "bx lr           \n\t" // Return to caller
      );
}

但这感觉也不太对。而且,它也不起作用--这里有些事情我做错了;也许我的指令没有正确地对齐,或者我还没有设置处理器来允许在这个位置从RAM中运行代码。

我该怎么办?

我得做最后一个选择。但是,我还是觉得我应该能做这样的事:

代码语言:javascript
复制
__attribute__((naked)) svc(char code)
{
    asm volatile ("scv %1"
         : /* No outputs */
         : "i" (code)    // Imaginary directive specifying an immediate argument
                         // as opposed to conventional "r"
          ); 
}

但是我在文档中找不到任何这样的选项,我无法解释如何实现这样的特性,所以它可能不存在。我该怎么做?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-07-07 20:42:15

您希望使用约束强制将操作数作为8位立即分配.对于ARM,这是约束I。所以你想

代码语言:javascript
复制
#define SVC(code) asm volatile ("svc %0" : : "I" (code) )

请参阅GCC文档,以获得所有约束的摘要--您需要查看特定处理器的注释,才能看到特定平台的约束。在某些情况下,您可能需要查看gcc源中的体系结构的.md (机器描述)文件,以获得全部信息。

还有一些很好的手臂特异性gcc博士这里。标题“输入和输出操作数”下的几页,它提供了一个包含所有ARM约束的表。

票数 25
EN

Stack Overflow用户

发布于 2014-06-06 10:53:20

正如克里斯·多德在有关宏的注释中所指出的那样,它不太起作用,但确实是这样的:

代码语言:javascript
复制
#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)
#define SVC(i)  asm volatile("svc #" STRINGIFY(i))

但是,请注意,如果将枚举值传递给它,则它将无法工作,只会传递一个#定义的值。

因此,Chris上面的答案是最好的,因为它使用了一个即时的值,这是所需的,至少对拇指指示是这样的。

票数 2
EN

Stack Overflow用户

发布于 2018-03-09 06:59:15

我的解决方案(“动态生成指令编码”):

代码语言:javascript
复制
#define INSTR_CODE_SVC      (0xDF00)
#define INSTR_CODE_BX_LR    (0x4770)

void svc_call(uint32_t svc_num)
{
    uint16_t instrs[2];

    instrs[0] = (uint16_t)(INSTR_CODE_SVC | svc_num);
    instrs[1] = (uint16_t)(INSTR_CODE_BX_LR);

    // PC = instrs (or 1 -> thumb mode)
    ((void(*)(void))((uint32_t)instrs | 1))();
}

它的工作原理和它的更好的开关-大小写变体,它需要~2kb ROM的256 svc。这个功能不需要放在RAM部分,闪存是可以的。如果svc_num应该是一个运行时变量,您可以使用它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11377453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档