【问题标题】:GCC inline assembly constants (ARM)GCC 内联汇编常量 (ARM)
【发布时间】:2015-06-03 00:27:01
【问题描述】:

有没有一种好方法可以将常量作为“参数”提供给内联汇编代码? 我正在尝试制作协处理器访问功能。 我尝试了两种方法:宏替换和扩展。

用法是这样的:

unsigned int read_ID_PFR1()
{
    READ_CP15(0, 0, 1, 1);
    return cp_reg_val;
}

宏观方法:

#define READ_CP15(opc, crn, crm, opc2) \
asm volatile (\
    "push {r0, r1}\n\t"\
    "mrc p15, opc, r0, crn, crm, opc2\n\t"\
    "ldr r1, =cp_reg_val\n\t"\
    "str r0, [r1]\n\t"\
    "pop {r0, r1}\n\t"\
    )

我认为参数 (opc, crn, ...) 没有扩展,因为它们是 用引号括起来。

扩展方法如下所示:

#define WRITE_CP15(opc, crn, crm, opc2) \
    asm volatile (\
        "push {r0, r1}\n\t"\
        "ldr r1, =cp_reg_val\n\t"\
        "ldr r0, [r1]\n\t"\
        "mcr p15, %[op], r0, c%[rn], c%[rm], %[op2]\n\t"\
        "pop {r0, r1}\n\t"\
        ::[op]"I"(opc), [rn]"I"(crn), [rm]"I"(crm), [op2]"I"(opc2):\
    )

除了“#”标记之外,这似乎做得更好。 (c%[rn] 扩展为 c#0)

【问题讨论】:

  • 我自己确实和_BKPT 在一起。您需要一个宏才能使用任何优化设置。有趣的旁注:如果不使用-O0,这也适用于内联函数。对于-O0,gcc 抱怨他可能无法解析常量。原因显然是在检查 asm 约束之前进行内联(我使用了 'i' IIRC)。

标签: c gcc inline-assembly


【解决方案1】:

不要将 push/pop 放入 inline asm 中。这不仅意味着你在 asm 中写的垃圾比你应该写的更多;它还排除了使用"m" 类型输入/输出约束,因为有效地址可能是堆栈指针相关的。而是使用类似的东西:

asm volatile ("mrc p15, opc, %0, crn, crm, opc2" : "=r"(cp_reg_val));

【讨论】:

    【解决方案2】:

    整理了一下:

    #define READ_CP15(retvar, opc, crn, crm, opc2) \
        asm volatile (\
            "mrc p15, %c[op], %[reg], c%c[rn], c%c[rm], %c[op2]\n\t"\
            :[reg] "=r" (retvar)\
            :[op]"I"(opc), [rn]"I"(crn), [rm]"I"(crm), [op2]"I"(opc2):\
        )
    

    那些 opc、crn、crm 和 opc2 需要在那里。它们是常数。 输出程序集是:

    @ 252 "../instr_comm.c" 1
        mrc p15, 0, r0, c0, c1, 1
    

    【讨论】:

      【解决方案3】:

      麦克墨菲再次中风。我花了几个小时弄清楚,但现在我发送了问题,我发现 '%' 和 '[name]' 之间的 'c' 可以做到 - 丢失了 '#'。

      这行得通:

      #define READ_CP15(opc, crn, crm, opc2) \
          asm volatile (\
              "push {r0, r1}\n\t"\
              "mrc p15, %c[op], r0, c%c[rn], c%c[rm], %c[op2]\n\t"\
              "ldr r1, =cp_reg_val\n\t"\
              "str r0, [r1]\n\t"\
              "pop {r0, r1}\n\t"\
              ::[op]"I"(opc), [rn]"I"(crn), [rm]"I"(crm), [op2]"I"(opc2):\
          )
      

      从(临时).s 文件中检查。

      【讨论】:

      • 为什么你自己的问题有两个答案?只删除一个。
      • Olaf,我的第二个回答是 R.. 的回答。
      • 这不是论坛。只需评论他的答案(仍然不确定为什么)。然而,他对推送/流行的东西是完全正确的。请注意,编译器无法遵循您在汇编代码中所做的事情。它基本上只是复制的(当然,还有一些补充)。
      • 最初的想法是 - 清理所有内容,以便 C 部分永远不会看到运行该程序集的任何影响,除了出现在变量中的结果。
      • 但是 gcc 会为你做到这一点!这样,它可以更好地优化周围的代码,例如它可以将任何需要的 push/pop 与它必须做的一些结合起来。或者只是不需要使用其他寄存器进行推送/弹出。好吧,那是你的代码,我不会继续毫无结果的讨论。我有一种强烈的印象,你并不完全理解内联汇编的概念。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多