【问题标题】:(inline assembly in C) Assembler messages: Error: unknown pseudo-op:(C 中的内联汇编)汇编程序消息:错误:未知伪操作:
【发布时间】:2016-02-03 23:16:24
【问题描述】:

我为 asm 内联程序集编写了一个简短的 C“包装器”函数,如下所示。汇编代码由一个 while 循环组成,使用 SSE2 计算几个向量点积。我在 x86 上的 Ubuntu 14.04 上使用 GCC 4.8.4。以下代码可以在

下“毫无问题”地组装

gcc -fpic -O2 -msse2 -S foo.c

但是当我这样做时

gcc -c foo.s

触发错误:

foo.c:汇编程序消息:
foo.c:2:错误:未知伪操作:`.while5'

我检查了汇编器输出“foo.s”,发现了一些奇怪的东西。

C 文件“foo.c”:

#include <emmintrin.h>

void foo (int kk, double *A, double *B, double *ALPHA, double *C, int ldc) {
   asm("movl %0, %%ecx\n\t"  /* kk -> %ecx */
       "movl %3, %%eax\n\t"  /* A -> %eax */
       "movl %4, %%edx\n\t"  /* B -> %edx */
       /* a while-loop */
       ".while%=\n\t"
       "movsd   (%%edx), %%xmm5\n\t"
       "unpcklpd %%xmm5, %%xmm5\n\t"
       "movapd  %%xmm5, %%xmm6\n\t"
       "movapd  (%%eax), %%xmm4\n\t"
       "mulpd   %%xmm4, %%xmm6\n\t"
       "movapd  16(%%eax), %%xmm7\n\t"
       "addl    $32, %%eax\n\t"
       "addpd   %%xmm6, %%xmm0\n\t"
       "mulpd   %%xmm7, %%xmm5\n\t"
       "addpd   %%xmm5, %%xmm1\n\t"
       "movsd   8(%%edx), %%xmm6\n\t"
       "addl    $16, %%edx\n\t"
       "unpcklpd %%xmm6, %%xmm6\n\t"
       "mulpd   %%xmm6, %%xmm4\n\t"
       "addpd   %%xmm4, %%xmm2\n\t"
       "mulpd   %%xmm6, %%xmm7\n\t"
       "addpd   %%xmm7, %%xmm3\n\t"
       "subl    $1, %%ecx\n\t"  /* kk-- */
       "testl   %%ecx, %%ecx\n\t"  /* kk = 0 ? */
       "jne .while%=\n\t"
        /* other input operands passing */
       "movl %5, %%ecx\n\t"  /* C -> %ecx */
       "movl %1, %%eax\n\t"  /* ALPHA -> %eax, then C0 -> %eax */
       "movl %2, %%edx\n\t"  /* ldc -> %edx */
       /* write-back */
       "movsd (%%eax), %%xmm7\n\t"
       "unpcklpd %%xmm7, %%xmm7\n\t"
       "leal (%%ecx,%%edx,8), %%eax\n\t"  /* C0=C+ldc */
       "mulpd %%xmm7, %%xmm0\n\t"
       "addpd (%%ecx), %%xmm0\n\t"
       "movapd %%xmm0, (%%ecx)\n\t"
       "mulpd %%xmm7, %%xmm2\n\t"
       "addpd (%%eax), %%xmm2\n\t"
       "movapd %%xmm2, (%%eax)\n\t"
       "mulpd %%xmm7, %%xmm1\n\t"
       "addpd 16(%%ecx), %%xmm1\n\t"
       "movapd %%xmm1, 16(%%ecx)\n\t"
       "mulpd %%xmm7, %%xmm3\n\t"
       "addpd 16(%%eax), %%xmm3\n\t"
       "movapd %%xmm3, 16(%%eax)\n\t"
       : /* no output operands */
       : "m"(kk), "m"(ALPHA), "m"(ldc), "m"(A), "m"(B), "m"(C)  /* input operands */
       : "eax", "edx", "ecx", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"  /* clobbers */ );
   }

汇编器输出(while 循环看起来很奇怪!)

.LFB503:
            .cfi_startproc
 #APP
 # 4 "foo.c" 1
            movl 4(%esp), %ecx
            movl 8(%esp), %eax
            movl 12(%esp), %edx
            .while5
            movsd   (%edx), %xmm5
            unpcklpd %xmm5, %xmm5
            movapd  %xmm5, %xmm6
            movapd  (%eax), %xmm4
            mulpd   %xmm4, %xmm6
            movapd  16(%eax), %xmm7
            addl    $32, %eax
            addpd   %xmm6, %xmm0
            mulpd   %xmm7, %xmm5
            addpd   %xmm5, %xmm1
            movsd   8(%edx), %xmm6
            addl    $16, %edx
            unpcklpd %xmm6, %xmm6
            mulpd   %xmm6, %xmm4
            addpd   %xmm4, %xmm2
            mulpd   %xmm6, %xmm7
            addpd   %xmm7, %xmm3
            subl    $1, %ecx
            testl   %ecx, %ecx
            jne .while5
            movl 20(%esp), %ecx
            movl 16(%esp), %eax
            movl 24(%esp), %edx
            movsd (%eax), %xmm7
            unpcklpd %xmm7, %xmm7
            leal (%ecx,%edx,8), %eax
            mulpd %xmm7, %xmm0
            addpd (%ecx), %xmm0
            movapd %xmm0, (%ecx)
            mulpd %xmm7, %xmm2
            addpd (%eax), %xmm2
            movapd %xmm2, (%eax)
            mulpd %xmm7, %xmm1
            addpd 16(%ecx), %xmm1
            movapd %xmm1, 16(%ecx)
            mulpd %xmm7, %xmm3
            addpd 16(%eax), %xmm3
            movapd %xmm3, 16(%eax)      
# 0 "" 2
#NO_APP
            ret
            .cfi_endproc

谁能告诉我发生了什么事?我不认为这是我的编译器的问题。我的代码一定有问题。谢谢!

【问题讨论】:

  • 你不能在程序集中进行 while 循环。
  • 您缺少一个冒号以使其成为标签:.while%=:。请注意,-S 不会汇编,它只会产生汇编输出,因此它也可能包含错误。
  • 那不是while循环,而是简单的标签和跳转。
  • @AlphaBetaGamma 啊!这应该是一个标签。通常,您不会缩进标签,并且如果您在 x86 上制作本地标签,则它应该以 .L 开头,因此是 .Lwhile:。我认为这是尝试使用名为 .while 的不存在的伪操作码。
  • 任何时候你在内联汇编中编写mov指令时,你应该寻找一种方法让编译器来做,这样在某些情况下它可以避免不必要的指令。例如对于 x86-64,args 已经全部在整数寄存器中,所以做一堆 mov reg,reg 而不是让编译器为你选择 regs 是愚蠢的。 (请参阅the x86 tag wiki 链接到我的内联 asm 示例,了解如何让编译器尽可能多地完成工作。)

标签: c gcc assembly inline-assembly


【解决方案1】:

因为您的 .while 未定义为标签,所以它被视为 [不存在] 伪操作。

变化:

".while%=\n\t"

进入:

".while%=:\n\t"

更新:

根据您的要求。

“伪操作”是 [术语] 与指令不对应的汇编指令。

一些例子:

.globl main 指定main 标签是一个全局变量。

.text 指定后面的内容应放在“文本”段中(.data 也是如此)。

. 前缀 [通常] 为伪操作保留。这就是您收到Error: unknown pseudo-op: 消息的原因。

如果您改为使用"while%=\n\t" [仍然错误,因为没有: 来表示标签],您会收到不同的消息:Error: no such instruction:

【讨论】:

  • 不客气!享受 sse2/xmm,它很有趣 [ 它被调试了 :-)]。
  • @CraigEstey 是的!我最近做了一个函数79 times faster,通过在 AVX 程序集而不是 C 代码中实现它。
  • @FUZxxl 哇!你是一个合我心意的人!我的 CPU 对 AVX 来说太旧了,但我一直渴望尝试一下。我还赞扬您有意识地在 asm [in a .s] 中编写此代码,而不是 [像许多人一样] 尝试将其填充到 [gcc] 内联 asm 中。最后,英特尔提供了足够丰富的指令集来实现真正的好东西(例如,仅三重参数就值得入场)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2012-03-01
  • 2015-03-17
相关资源
最近更新 更多