使用带有立即值的指令的GCC内联汇编

Kev*_*eer 10 c assembly gcc arm inline-assembly

问题

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

在此输入图像描述

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

这使我很难以可读的方式构建我的界面.它需要如下代码:

asm volatile( "svc #0");
Run Code Online (Sandbox Code Playgroud)

当我更喜欢像

svc(SVC_YIELD);
Run Code Online (Sandbox Code Playgroud)

但是,我无法构造这个函数,因为SVC指令需要立即参数,当值通过寄存器传入时我无法提供.

内核:

对于后台,svc指令在内核中解码如下

#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
Run Code Online (Sandbox Code Playgroud)

这个案例陈述正在迅速失控,但我认为没有解决这个问题.欢迎任何建议.

我试过的

带有寄存器参数的SVC

我最初考虑过

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv r0"); 
}
Run Code Online (Sandbox Code Playgroud)

但是,当然,这不起作用,因为SVC需要寄存器参数.

蛮力

蛮力企图解决问题看起来像:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

动态生成指令编码

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

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
      );
}
Run Code Online (Sandbox Code Playgroud)

但这也感觉不对劲.此外,它不起作用 - 这里有一些我做错了; 也许我的指令没有正确对齐,或者我没有设置处理器以允许在此位置从RAM运行代码.

我该怎么办?

我必须研究最后一个选项.但是,感觉我应该能够做到这样的事情:

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv %1"
         : /* No outputs */
         : "i" (code)    // Imaginary directive specifying an immediate argument
                         // as opposed to conventional "r"
          ); 
}
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*odd 21

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

#define SVC(code) asm volatile ("svc %0" : : "I" (code) )
Run Code Online (Sandbox Code Playgroud)

有关所有constaints的摘要,请参阅GCC文档 - 您需要查看特定于处理器的注释以查看特定平台的约束.在某些情况下,您可能需要查看.mdgcc源代码中架构的(机器描述)文件以获取完整信息.

还有一些不错的特定ARM-GCC文档在这里.在"输入和输出操作数"标题下面几页,它提供了所有ARM约束的表格

  • +1,这个答案比接受的答案要好得多,因为它适用于任何整数常量表达式,而不仅仅是文字. (4认同)