【问题标题】:AVR GCC, assembly C stub functions, eor and the required constant valueAVR GCC、汇编 C 存根函数、eor 和所需的常量值
【发布时间】:2016-10-29 15:02:07
【问题描述】:

我有这个代码:

uint16_t swap_bytes(uint16_t x)
{
    asm volatile(
        "eor, %A0, %B0"     "\n\t"
        "eor, %B0, %A0"     "\n\t"
        "eor, %A0, %B0"     "\n\t"
        : "=r" (x)
        : "0" (x)
    );
    return x;
}

翻译(通过 avr-gcc version 4.8.1-std=gnu99 -save-temps)为:

.global swap_bytes
    .type   swap_bytes, @function
swap_bytes:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
/* #APP */
 ;  43 "..\lib\own\ownlib.c" 1
    eor, r24, r25
    eor, r25, r24
    eor, r24, r25

 ;  0 "" 2
/* #NOAPP */
    ret
    .size   swap_bytes, .-swap_bytes

但是编译器会这样抱怨:

|65|Error: constant value required|
|65|Error: garbage at end of line|
|66|Error: constant value required|
|66|Error: garbage at end of line|
|67|Error: constant value required|
|67|Error: garbage at end of line|
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

提到的行是带有eor 命令的行。为什么编译器会出现问题?寄存器甚至更高(> = r16),几乎所有操作都是可能的。 constant value required 对我来说听起来像是需要文字……我不明白。

【问题讨论】:

  • gcc 有内置插件。为什么不使用那些?无论如何,您都依赖于编译器。为什么不使用纯 C?
  • 我支持 Olaf:如果可以,请使用内置函数。但是,如果您必须使用内联汇编,我想知道您的问题是否是“额外”逗号。谷歌搜索 avr eor 会出现 eor r4,r4eor r0,r22(注意 eor 命令后没有逗号)。我不是 avr 专家,但这是我首先要尝试的。
  • f#*k!你说得对。不应该有,。无论如何,AVR 都是微控制器,所以程序空间很紧。 3 指令对于 C 来说是无与伦比的。再次感谢你们!

标签: c gcc assembly inline-assembly avr-gcc


【解决方案1】:

只是为了澄清未来的谷歌员工:

eor, r24, r25

在 eor 之后有一个额外的逗号。这应该写成:

eor r24, r25

我还鼓励您(再次)考虑使用 gcc 的 __builtin_bswap16。如果您不熟悉 gcc 的“内置”函数,它们是编译器内置的函数,并且(尽管看起来像函数)通常是内联的。它们是由了解各种处理器的所有细节的人编写和优化的,并且可以考虑到您可能没有考虑过的事情。

我理解保持代码尽可能小的愿望。而且我接受您的特定处理器上的这个内置程序可能(以某种方式)产生次优代码(我假设您已经检查过?)。另一方面,它可能产生完全相同的代码。或者它可能会使用一些更聪明的技巧来做到这一点。或者它可能会交织来自周围代码的指令以利用流水线(或其他一些我从未听说过的 avr 特定的东西,因为我不会说 'avr')。

此外,请考虑以下代码:

int main()
{
   return __builtin_bswap16(12345);
}

您的代码总是需要 3 条指令来处理交换。但是,使用内置函数,编译器可以识别 arg 是常量并在编译时而不是在运行时计算值。很难比这更有效率。

我还可以指出“更易于支持”的好处。编写内联 asm 很难正确完成。未来的维护者讨厌碰它,因为他们永远不确定它是如何工作的。当然,内置将更加跨平台便携。

仍然不相信?我的最后一个建议:即使您修复了逗号,您的内联 asm 代码仍然不太正确。考虑这段代码:

int main(int argc, char *argv[])
{
   return swap_bytes(argc) + swap_bytes(argc);
}

由于您编写swap_bytes 的方式(即使用volatile),gcc 必须计算两次该值(参见volatile 的定义)。如果您省略了 volatile (或者如果您使用了正确执行此操作的内置函数),它会意识到 argc 不会更改并重新使用第一次调用的输出。我有没有提到正确编写内联 asm 很困难?

我不知道您的代码、限制、专业水平或要求。也许您的解决方案确实是最好的。我能做的就是鼓励您在生产代码中使用内联 asm 之前仔细考虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多