2017-04-19 107 views
1

我想组装一个使用ARM的CRC指令的文件。汇编程序产生错误Error: selected processor does not support 'crc32b w1,w0,w0'GAS是否从内联汇编生成指令?

有运行时检查到位,所以我们对这条指令很安全。该技术在i686和x86_64上正常工作。例如,我可以组装使用英特尔CRC intrinsicsSHA 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添加到CFLAGSCXXFLAGS

此外,发行版编译为“最低能力”的机器,所以我们希望硬件加速例程可用。当库由Linaro等发行版提供时,两个代码路径(软件CRC和硬件加速CRC)将可用。


该机器是一个LeMaker HiKey,它是ARMv8/Aarch64。它的A53处理器具有CRC和加密(CRC和加密是可选的架构下):

$ 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的-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++ -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 
+1

我没有一个环境中测试这一点,但它听起来像是你需要的是'.arch_extension name'。也许直接添加到这个asm指令。根据[docs](https://sourceware.org/binutils/docs/as/ARM-Directives.html),这允许您*为增加或删除扩展到正在编译为*的架构。如果失败了,可能会添加'.arch name'作为'basic'asm的“顶级”位? –

+0

还是有更多的限制,我错过了?向像这样的asm指令添加指令并不是什么新东西。人们一直在使用它来将intel风格的汇编程序放入asm指令中。 –

+0

@David - 谢谢。我沿着同样的思路思考。唉,A-32,Aarch32和Aarch64不是IA32。我昨天尝试了'.arch_extension',但是它导致了错误。 '.arch_extension'需要2016年的Binutils 2.26。2.26支持Aarch32和Aarch64。另请参阅Linaro Toolchain邮件列表上的[Error:unknown pseudo-op:'.arch_extension'](https://lists.linaro.org/pipermail/linaro-toolchain/2017-April/006112.html)。 – jww

回答

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 
} 

由预处理块中注释掉的第二个建议由尼克克利夫顿在Binutils mailing list。这个想法是GCC使用基于-march=XXX的ISA生成代码,因此,如果我们增加能够通过汇编程序的能力并不重要。因为我们不希望修改.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