我正在尝试手动发布ARMv7 movt
和movw
指令以进行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组装movt
和movw
指令?
答案 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位操作码(4618
和4770
),而前两条是两对分开的16位操作码(f241 2334
和f2c1 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");