由于本地标签,AIX汇编程序出现1252-142语法错误

时间:2018-08-16 04:49:18

标签: c aix inline-assembly powerpc

使用内联汇编和本地标签时,我遇到了汇编器错误。编译器为GCC,计算机为运行AIX的PowerPC。代码reads the timestamp(大致等效于rdtsc):

static unsigned long long cpucycles( void )
{
  unsigned long long int result=0;
  unsigned long int upper, lower,tmp;
  __asm__ __volatile__ (
                "0:             \n\t"
                "mftbu   %0     \n\t"
                "mftb    %1     \n\t"
                "mftbu   %2     \n\t"
                "cmpw    %2,%0  \n\t"
                "bne-    0b     \n\t"
                : "=r"(upper),"=r"(lower),"=r"(tmp)
                : :
                );
  result = upper;
  result = result<<32;
  result = result|lower;
  return(result);
}

汇编代码后,结果为:

gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 103: 1252-142 Syntax error.

使用--save-temps进行编译并检查test.s

$ cat -n test.s
...

   101  L..5:
   102   # 58 "test.c" 1
   103          0:
   104          mftbu   10
   105          mftb    9
   106          mftbu   8
   107          cmpw    8,10
   108          bne     0b
   109

看起来汇编程序在使用本地标签时遇到了麻烦。基于IBM的Use of inline assembly和本地标签,我认为标签和分支的使用正确:

  

内联汇编中只有一些本地标签是合法的。你可能会看到   标签,例如代码C中的0和1。它们是   指令bne- 0b\n\tbne 1f\n\t。 (后缀f   label表示分支指令后面的标签,b表示   一个领先)

IBM的error message for 1252-142并不是很有帮助:

  

原因

     

如果在组装过程中发生错误,但不是   在消息目录中定义时,将使用此通用错误消息。   该消息涵盖伪操作和指令。因此,   使用说明将毫无用处。

     

操作

     

确定意图和源代码行的构造,然后咨询   具体说明文章,以更正源代码行。

问题出在哪里,我该如何解决?


基于@Eric在评论中的建议:

__asm__ __volatile__ (
  "\n0:           \n\t"
  "mftbu   %0     \n\t"
  "mftb    %1     \n\t"
  "mftbu   %2     \n\t"
  "cmpw    %2,%0  \n\t"
  "bne-    0b     \n\t"
  : "=r"(upper),"=r"(lower),"=r"(tmp)
);

导致下移一行的问题:

gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 104: 1252-142 Syntax error.

但是标签似乎在第0列:

 103
 104  0:
 105          mftbu   10
 106          mftb    9
 107          mftbu   8
 108          cmpw    8,10
 109          bne-    0b

2 个答案:

答案 0 :(得分:1)

gcc不会直接发出机器代码。它将其asm输出提供给系统汇编程序。您可以将gcc配置为使用其他汇编程序,例如GAS,但是显然您使用的计算机上的默认设置具有使用AIX汇编程序的GCC。

显然,与GNU汇编器不同,AIX的汇编器不支持数字标签。当您提及的文章使用0之类的标签时,您链接的文章可能是Linux(偶然或故意)。


最简单的解决方法可能是让GCC自动为标签编号,而不是使用本地标签,因此可以在同一编译单元中多次内联/展开同一asm块,而不会引起符号名冲突。 %= expands to a unique number in every instance.

IDK,如果L..使其成为文件本地标签(不会使调试信息或符号表混乱)。在Linux / ELF / x86上,.L是常规前缀,但是您具有编译器生成的L..标签。

__asm__ __volatile__ (
            "L..again%=:    \n\t"
            "mftbu   %0     \n\t"
            "mftb    %1     \n\t"
            "mftbu   %2     \n\t"
            "cmpw    %2,%0  \n\t"
            "bne-    L..again%="
            : "=r"(upper),"=r"(lower),"=r"(tmp)
            : :
            );

或者对于这个特定的asm用例,可能会有一个内置函数来读取时间戳寄存器,该寄存器将像这样编译为asm。

答案 1 :(得分:-1)

除了@Peter的答案外,我还在How to have GCC combine “move r10, r3; store r10” into a “store r3”?上找到了这个答案。另一个问题也在AIX上引起了问题。

这是另一个问题的代码,在AIX上导致了1252-142:

uint32_t val;
__asm__ __volatile__ (
    "1:                            \n"  // retry label
    #if __BIG_ENDIAN__
    ".byte 0x7c, 0x60, 0x05, 0xe6  \n"  // r3 = darn 3, 0
    #else
    ".byte 0xe6, 0x05, 0x60, 0x7c  \n"  // r3 = darn 3, 0
    #else
    "cmpwi 3,-1                    \n"  // r3 == -1?
    "beq 1b                        \n"  // again on failure
    "mr %0,3                       \n"  // val = r3
    : "=r" (val) : : "r3", "cc"
);

解决方法是,不要使用标签。只需使用位移:

uint32_t val;
__asm__ __volatile__ (
    // "1:                         \n"  // retry label
    #if __BIG_ENDIAN__
    ".byte 0x7c, 0x60, 0x05, 0xe6  \n"  // r3 = darn 3, 0
    #else
    ".byte 0xe6, 0x05, 0x60, 0x7c  \n"  // r3 = darn 3, 0
    #else
    "cmpwi 3,-1                    \n"  // r3 == -1?
    // "beq 1b                     \n"  // again on failure
    "beq .-8                       \n"  // again on failure
    "mr %0,3                       \n"  // val = r3
    : "=r" (val) : : "r3", "cc"
);

在上面的代码中,我需要跳回2条指令以重新执行darn 3, 0。每个指令均为4字节,因此跳转为-8。但是,跳转目标需要可重定位,因此使用了表达式.-8。点表示“这里”。

它在AIX和Linux上均可使用。