错误:宽度后缀在ARM模式下无效

时间:2019-05-21 00:17:58

标签: arm clang inline-assembly

我正在尝试手动发布ARMv7 movtmovw指令以进行cpu功能测试。我在用Clang捕获编译错误。

下面是测试程序。据ARM人士称,.inst.w是做到这一点的方法。它可以正确处理big-endian和little-endian,并将代码放在.text部分而不是data部分中。

$ cat test.cxx
int test()
{
  int a;
  asm volatile (
        ".inst.w 0xf2412334  \n\t"   // movw r3, 0x1234
        ".inst.w 0xf2c12334  \n\t"   // movt r3, 0x1234
        "mov %0, r3          \n\t"   // mov [a], r3
        : "=r" (a) : : "r3");
  return a;
}

GCC很好:

$ g++ -O1 -march=armv7-a test.cxx -c
$ objdump --disassemble test.o
...
00000000 <_Z4testv>:
   0:   f241 2334       movw    r3, #4660       ; 0x1234
   4:   f2c1 2334       movt    r3, #4660       ; 0x1234
   8:   4618            mov     r0, r3
   a:   4770            bx      lr

但是,叮当声:

$ clang++ -O1 -march=armv7-a test.cxx -c
test.cxx:5:2: error: width suffixes are invalid in ARM mode
        ".inst.w 0xf2412334  \n\t"   // movw r3, 0x1234
        ^
<inline asm>:1:2: note: instantiated into assembly here
        .inst.w 0xf2412334
        ^
test.cxx:5:25: error: width suffixes are invalid in ARM mode
        ".inst.w 0xf2412334  \n\t"   // movw r3, 0x1234
                               ^
<inline asm>:2:2: note: instantiated into assembly here
        .inst.w 0xf2c12334
        ^
2 errors generated.

如果我将.inst.w更改为.inst,则Clang会产生垃圾:

$ clang++ -O1 -march=armv7-a test.cxx -c
$ objdump --disassemble test.o
...
00000000 <_Z4testv>:
   0:   f2412334        vcge.s8 d18, d1, d20
   4:   f2c12334        vbic.i32        d18, #5120      ; 0x00001400
   8:   e1a00003        mov     r0, r3
   c:   e12fff1e        bx      lr

我已验证Clang在定义__GNUC__,因此它应该能够使用此代码。

如何让Clang组装movtmovw指令?

1 个答案:

答案 0 :(得分:1)

主要区别在于您的GCC已配置为默认为拇指模式,而没有clang。

ARM有两个不同的32位指令集,即ARM和Thumb,即使指令名相似,编码也不同。 ARM指令集将所有指令编码为固定长度的32位指令,而Thumb最初是小得多的指令集,所有指令均为16位。自从Thumb2(ARMv7就是这种情况)以来,这些指令可以是一条16位指令,也可以是两条16位指令对。

您显示的反汇编表明:

   0:   f241 2334       movw    r3, #4660       ; 0x1234
   4:   f2c1 2334       movt    r3, #4660       ; 0x1234
   8:   4618            mov     r0, r3
   a:   4770            bx      lr

后两条指令是普通的16位操作码(46184770),而前两条是两对分开的16位操作码(f241 2334f2c1 2334)带有空格。

但是clang反汇编不会将操作码分成两半,并且对于所有指令都具有完整的32位操作码:

   0:   f2412334        vcge.s8 d18, d1, d20
   4:   f2c12334        vbic.i32        d18, #5120      ; 0x00001400
   8:   e1a00003        mov     r0, r3
   c:   e12fff1e        bx      lr

在这种情况下,将-mthumb传递给Clang应该具有与GCC相同的行为,反之亦然,将-marm传递给GCC应该在此处重现相同的故障。

.w的后缀.inst表示该值应作为宽32位指令(而不是窄16位指令)来处理,这仅在Thumb模式下才有意义。 IIRC,GCC(一段时间以来)和Clang(版本8起)都应该能够推断出没有后缀.w的Thumb指令。

您可能想要这样的事情,而不是强迫编译器进入一种或另一种模式:

  asm volatile (
#ifdef __thumb__
        ".inst.w 0xf2412334  \n\t"   // movw r3, 0x1234
        ".inst.w 0xf2c12334  \n\t"   // movt r3, 0x1234
#else
        ".inst   0xe3013234  \n\t"   // movw r3, 0x1234
        ".inst   0xe3413234  \n\t"   // movt r3, 0x1234
#endif
        "mov %0, r3          \n\t"   // mov [a], r3
        : "=r" (a) : : "r3");