我正在尝试组装使用ARM的CRC指令的文件。汇编程序产生错误 Error: selected processor does not support 'crc32b w1,w0,w0'
。
有运行时检查,所以我们对指令是安全的。该技术在i686和x86_64上运行良好。例如,我可以汇编使用英特尔CRC intrinsics或SHA Intrinsics而不使用-mcrc
或-msha
的文件(并且在没有这些功能的计算机上)。
以下是测试用例:
$ cat test.cxx
#include <arm_neon.h>
#define GCC_INLINE_ATTRIB __attribute__((__gnu_inline__, __always_inline__, __artificial__))
#if defined(__GNUC__) && !defined(__ARM_FEATURE_CRC32)
__inline unsigned int GCC_INLINE_ATTRIB
CRC32B(unsigned int crc, unsigned char v)
{
unsigned int r;
asm ("crc32b %w2, %w1, %w0" : "=r"(r) : "r"(crc), "r"((unsigned int)v));
return r;
}
#else
// Use the intrinsic
# define CRC32B(a,b) __crc32b(a,b)
#endif
int main(int argc, char* argv[])
{
return CRC32B(argc, argc);
}
结果如下:
$ g++ test.cxx -c
/tmp/ccqHBPUf.s: Assembler messages:
/tmp/ccqHBPUf.s:23: Error: selected processor does not support `crc32b w1,w0,w0'
将ASM代码放在源文件中并使用不同的选项进行编译是不可行的,因为CRC32B
也将在C ++头文件中使用。
如何让GAS汇总指令?
GCC的配置和选项是我们尝试以这种方式做事的原因。用户不会阅读手册,因此他们无法将-march=armv8-a+crc+crypto -mtune=cortex-a53
添加到CFLAGS
和CXXFLAGS
。
此外,发行版汇编成一个能力最差的&#34;机器,所以我们想要硬件加速例程。当库由Linaro这样的发行版提供时,两个代码路径(软件CRC和硬件加速CRC)都将可用。
该机器是LeMaker HiKey,它是ARMv8 / Aarch64。它有一个带有CRC和Crypto的A53处理器(CRC和Crypto在架构下是可选的):
$ cat /proc/cpuinfo
Processor : AArch64 Processor rev 3 (aarch64)
processor : 0
...
processor : 7
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: AArch64
GCC缺少大多数通常默认存在的定义:
$ g++ -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
#define __aarch64__ 1
#define __AARCH64_CMODEL_SMALL__ 1
#define __AARCH64EL__ 1
使用GCC&#39; -march=native
不适用于ARM:
$ g++ -march=native -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
cc1: error: unknown value ‘native’ for -march
和Clang:
$ clang++ -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
#define __AARCH64EL__ 1
#define __ARM_64BIT_STATE 1
#define __ARM_ACLE 200
#define __ARM_ALIGN_MAX_STACK_PWR 4
#define __ARM_ARCH 8
#define __ARM_ARCH_ISA_A64 1
#define __ARM_ARCH_PROFILE 'A'
#define __ARM_FEATURE_CLZ 1
#define __ARM_FEATURE_DIV 1
#define __ARM_FEATURE_FMA 1
#define __ARM_FEATURE_UNALIGNED 1
#define __ARM_FP 0xe
#define __ARM_FP16_FORMAT_IEEE 1
#define __ARM_FP_FENV_ROUNDING 1
#define __ARM_NEON 1
#define __ARM_NEON_FP 0xe
#define __ARM_PCS_AAPCS64 1
#define __ARM_SIZEOF_MINIMAL_ENUM 4
#define __ARM_SIZEOF_WCHAR_T 4
#define __aarch64__ 1
GCC版本:
$ gcc -v
...
gcc version 4.9.2 (Debian/Linaro 4.9.2-10)
GAS版本:
$ as -v
GNU assembler version 2.24 (aarch64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.24
答案 0 :(得分:2)
这个答案来自王炯Binutils mailing list。它绕过了GAS的架构要求,并与GCC配合使用:
__inline unsigned int GCC_INLINE_ATTRIB
CRC32W(unsigned int crc, unsigned int val)
{
#if 1
volatile unsigned int res;
asm ("\n"
"\t" ".set reg_x0, 0\n"
"\t" ".set reg_x1, 1\n"
"\t" ".set reg_x2, 2\n"
"\t" ".set reg_x3, 3\n"
"\t" ".set reg_x4, 4\n"
"\t" ".set reg_x5, 5\n"
"\t" ".set reg_x6, 6\n"
"\t" ".set reg_x7, 7\n"
"\t" "#crc32w %w0, %w1, %w2\n"
"\t" ".inst 0x1ac04800 | (reg_%2 << 16) | (reg_%1 << 5) | (reg_%0)\n"
: "=r"(res) : "r"(crc), "r"(val)
);
return res;
#else
volatile unsigned int res;
asm (".cpu generic+fp+simd+crc+crypto \n"
"crc32w %w0, %w1, %w2 \n"
: "=r"(res) : "r"(crc), "r"(val));
return res;
#endif
}
预处理器块注释的第二个是由Nick Clifton在Binutils mailing list上提出的。这个想法是GCC使用基于-march=XXX
的ISA生成代码,所以如果我们增加通过汇编程序的能力并不重要。我们决定采用Wang的答案,因为我们不希望修改.cpu
的潜在副作用。
使用GCC 4.8和Binutils 2.24进行验证:
$ g++ -O1 test.cxx -c
$ objdump --disassemble test.o
test.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <main>:
0: 12001c01 and w1, w0, #0xff
4: 1ac14800 crc32w w0, w0, w1
8: d65f03c0 ret