【问题标题】:Invalid 'asm': operand is not a condition code, invalid operand code 'c'无效的“asm”:操作数不是条件代码,无效的操作数代码“c”
【发布时间】:2017-08-03 01:31:49
【问题描述】:

我正在尝试从这里https://github.com/Ericson2314/Voxlap 在 linux 上构建 Voxlap,当我尝试这样做时,我收到一条关于内联程序集的错误消息:

source/sdlmain.cpp: In function ‘void fpuinit(long int)’:
source/sdlmain.cpp:1814:3: error: invalid 'asm': operand is not a condition code, invalid operand code 'c'
);
^

source/sdlmain.cpp:1814:3: error: invalid 'asm': operand is not a condition code, invalid operand code 'c'
source/sdlmain.cpp:1814:3: error: invalid 'asm': operand is not a condition code, invalid operand code 'c'
source/sdlmain.cpp:1814:3: error: invalid 'asm': operand is not a condition code, invalid operand code 'c'

有问题的代码在这里:

static long fpuasm[2];
static inline void fpuinit (long a)
{
    __asm__ __volatile__
    (
        "fninit\n"
        "fstcww %c[fp]\n"
        "andb   $240, %c[fp]+1(,1)\n"
        "orb    %%al, %c[fp]+1(,1)\n"
        "fldcww %c[fp]\n"
        :
        : "a" (a), [fp] "p" (fpuasm)
        : "cc"
    );
}

编译器错误指向这部分

 : "cc"

任何帮助破译错误消息或实际问题将不胜感激,谢谢

【问题讨论】:

  • 我的问题是关于构建一个库并寻求帮助以破译错误消息或有关此程序集细节的解释以及为什么输出此错误。除了提供代码和错误以及我正在构建的内容之外,我无能为力。
  • 错误消息告诉您您使用的c 操作数代码不正确。 c 操作数代码是%c[fp] 中的字母c。这是说操作数[fp] "p" (fpuasm) 不是条件代码,它似乎不是。至于实际问题,很难说您没有提供 MCVE 可能会发生什么,但我猜您正在尝试为非 x86 目标编译此代码。
  • 我猜你是在一些基于 Ubuntu >= 16.10 的发行版上,并且默认构建一个与位置无关的可执行文件。尝试添加 G++ 编译器选项 -fno-pie 。有问题的代码没有考虑到"p" 约束在默认-fpie 下无法按预期工作(此默认值在 Ubuntu >= 16.10 上已更改)。
  • @MichaelPetch 'c' 操作数修饰符/代码似乎有两个目的。似乎它正在使用它抱怨的未记录目的,因为操作数不能作为常量发出,这似乎是正确的。我的猜测是代码依赖于打开的优化。由于使用了 -mfpmath-sse 标志,这段代码似乎也不会做任何有用的事情。
  • %[fp] 生成的指令看起来像fstcww _ZL6fpuasm@GOTOFF(%ecx) 当然这与位置无关,但不能转换为常量。我认为这种情况的错误消息并没有真正说明到底发生了什么。

标签: assembly x86 g++ inline-assembly


【解决方案1】:

正如 Michael Petch 解释的那样,问题的直接原因可能是因为 Ubuntu 现在附带了一个默认创建位置无关可执行文件 (PIE) 的 GCC 版本。当编译器生成与位置无关的代码 (PIC) 时,asm 语句不起作用。您可能可以将代码替换为以下代码,因为它应该是等效的:

// set up the x87 FPU, ignoring the SSE MXCSR used for normal FP operations in x86-64 or 32-bit with -mfpmath=sse
static inline void fpuinit (long a)
{
    asm volatile (
        "mov %1, %0\n\t"
        "fninit\n\t"
        "fldcw %0\n"
        : "=m" (*(short *)fpuasm)    // *OUTPUT* operand, not input
        : "ir" ((short) (0x037F & 0xF0FF | (a & 0xFF) << 8)));
}

或者更好的是,在 asm 之外分配给 fpuasm(如果您只想设置前 2 个字节,则使用 memcpy),或者根本不分配,只使用本地 tmp。 (两种方式的源 + 编译器生成的 asm on the Godbolt compiler explorer)。这仍然有关于严格别名的警告,但至少我们告诉编译器这个函数写入fpuasm,而不是读取它。


这取代了尴尬的"p"“指针”约束和c“常量”操作数修饰符,它需要使其与简单的"m"“内存”约束一起工作。无论它是否被编译为 PIC,这都有一个优势。它也适用于 32 位和 64 位目标。

我还利用 FNINIT 指令将 FPU 控制字设置为已知状态 (0x037F) 因此无需使用 FSTCW 指令来读取它这一事实,擅自优化了代码。

使用两个内存目标 AND/OR 指令而不是在寄存器中准备值也是愚蠢的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    相关资源
    最近更新 更多