【问题标题】:Using C headers in C++ code in GNU. Error including inline assembly: impossible constraint in 'asm'在 GNU 的 C++ 代码中使用 C 头文件。包括内联汇编的错误:“asm”中的不可能约束
【发布时间】:2013-03-29 23:14:25
【问题描述】:

我有一个奇怪的。我正在使用供应商的头文件开发嵌入式系统。我正在使用 GCC 4.6.3 编译文件。我想在我的代码中使用 C++,我有错误我无法弄清楚。我正在运行一个供应商示例程序,我所做的只是将 main.c 文件的名称更改为 main.cpp。因此,我假设 C++ 编译器正在解释头文件。其中之一包含以下几行:

__attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc %0\n" \
         "bx r14" : : "I" (number) : "r0" \
     ); \
}

如果文件名为 main.c,则文件编译正确,我认为这是因为 C 编译器正在处理该文件。如果我使用 C++,我得到的错误是

error: impossible constraint in 'asm'

但同样,我对 C 编译器没有任何问题。我需要在 C++ 文件中调用使用此定义的函数。我考虑过编写保留在 c 端并链接到它们的包装函数,但这将是一个真正的痛苦,而且效率较低。有什么建议么?

【问题讨论】:

  • 如果它在头文件中,你记得extern "C"吗?
  • 我最后尝试了它,但我没想到它会起作用。据我所知, extern "C" 只影响链接,而不是编译。我认为我得到的是编译错误,而不是链接错误。 (还是)感谢你的建议。 stackoverflow.com/questions/1041866/…
  • 我明白了,我跳过了它是宏的部分:P
  • 它也可能会影响 ABI。
  • 您确定 C++ 编译找到了交叉编译器,并且您不是不小心使用了宿主编译器吗?

标签: c++ gcc embedded arm inline-assembly


【解决方案1】:

svc 也称为swiARM/Thumb 软件中断 指令。它只需要常量,但它们与其他寄存器常量不同。即mov r0, #4096。如果您希望指定立即数,则需要使用预处理器和令牌粘贴。 number 不能是变量寄存器

#define syscall(number) __attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc " #number "\n" \
         "bx r14" : : : "r0" \
     ); \
  }

会起作用。 注意:#'C' 预处理器字符串化。另请注意,查看SVC 编号是低效的,因为它在I-CACHE 中,并且检查需要D-CACHE。通常它总是constant 并且 function 编号被传递到一个寄存器中以实现更快的系统调用。

gcc 手册说,

'I'- 在数据中作为立即操作数有效的整数 处理指令。即0范围内的整数 以 2 的倍数旋转到 255

这是典型的数据处理操作数 - 立即,ARM ARM 的 A5.1.3 节。 SVC 操作数在 thumb 模式下是固定的 8 位或在 ARM 模式下是固定的 24 位。可能有一些我不知道的其他约束,但只要将数字常量传递给宏,至少预处理器的字符串化将起作用。

我想这是幸运的,这从 gcc 开始工作,不幸的是 g++ 没有。您可以通过使用-S 并使用这两种工具查看(并发布)输出来获得进一步的见解。

编辑:您的代码似乎与gcc-4.7.2 一起使用,但number 在我的情况下是const int 本地的,number 的使用可能是问题所在。也许它有从“C”到“C++”的微妙语义变化。

【讨论】:

  • 感谢您的帮助。你的编辑让我走上了正轨。它是数字的数据类型。供应商使用的常量被定义为枚举,它改变了 C 和 C++ 之间的类型。我已将它们更改为#define's,它正在发挥作用。谢谢。
  • 与其将一大堆枚举更改为#defines,我发现我可以简单地添加一个带有强制类型转换的局部变量。
  • 感谢 KendrickTaylor,为我完成了这项工作!我想我们都在使用 nRF51? :) @ChristopherMason,你能粘贴一个代码 sn-p 吗?
  • 这个演员表适合我:"bx r14" : : "I" ((uint16_t)number) : "r0" 我在本地文件中执行此操作并使用包含顺序优先包含它,这样就不必修改 Nordic SDK。
  • 好的,行为很可能会根据 gcc 版本和优化级别而改变。即,它现在可能适用于演员表,但如果您升级和/或更改优化级别,您可能会遇到麻烦。要点是编译器必须能够推断出该值是一个常量。例如,使用-O0 编译可能不起作用,因为编译器可能会将内容留在寄存器中。优化级别越高,演员表就越有可能起作用。
【解决方案2】:

检查GCC manual(内联汇编程序)以了解您机器的约束的确切含义。旧的 GCC 版本在检查约束方面是出了名的草率,也许你被这个咬了。奇怪的是gccg++(相同版本?)处理代码的方式不同,它只是可能是一个编译器错误,但我认为只有在所有其他解释都用尽之后.

【讨论】:

  • 谢谢,我去看看。 gcc 和 g++ 都是同一个版本。
猜你喜欢
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 2019-09-20
相关资源
最近更新 更多