2017-04-19 17 views
1

ARM의 CRC 명령어를 사용하는 파일을 어셈블하려고합니다. 어셈블러에서 Error: selected processor does not support 'crc32b w1,w0,w0'이라는 오류가 발생합니다.GAS가 인라인 어셈블리에서 명령어를 생성합니까?

런타임 검사가 있으므로 실행시 안전합니다. 이 기술은 i686 및 x86_64에서 정상적으로 작동합니다. 예를 들어 또는 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); 
} 

을 그리고 여기 결과입니다 CRC32B이되기 때문에 가능한

$ g++ test.cxx -c 
/tmp/ccqHBPUf.s: Assembler messages: 
/tmp/ccqHBPUf.s:23: Error: selected processor does not support `crc32b w1,w0,w0' 

소스 파일에 ASM 코드를 배치하고 다른 옵션과 함께 컴파일되지 않는다 C++ 헤더 파일에도 사용됩니다.

GAS로 명령어를 어셈블하려면 어떻게해야합니까?


GCC의 구성 및 옵션이 이러한 방식으로 작업을 수행하는 이유입니다. 사용자는 설명서를 읽지 않으므로 -march=armv8-a+crc+crypto -mtune=cortex-a53CFLAGSCXXFLAGS에 추가하지 않습니다.

또한 배포판은 "성능이 가장 낮은"컴퓨터로 컴파일되므로 하드웨어 가속 루틴을 사용할 수 있기를 원합니다. 라이브러리가 Linaro와 같은 배포판에서 제공되면 두 코드 경로 (소프트웨어 CRC 및 하드웨어 가속 CRC)를 사용할 수 있습니다.


기계는 LeMaker HiKey이며 ARMv8/Aarch64입니다. 그것은 CRC 및 암호화를 가진 A53 프로세서가 (CRC 및 암호화는 아키텍처에 따라 선택 사항입니다) :

$ g++ -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)' 
#define __aarch64__ 1 
#define __AARCH64_CMODEL_SMALL__ 1 
#define __AARCH64EL__ 1 

사용 :

$ 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는 평소의 대부분은 하나가 기본적으로 존재하는 것으로 예상하고 정의합니다 부족 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) 

가스 버전 :

$ 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/bin/tools/docs/as/ARM-Directives.html)에 따르면, *를 위해 컴파일되는 아키텍처에 확장을 추가하거나 제거 할 수 있습니다. 아마도'.arch name'을 '기본'asm의 "최상위 레벨"비트로 추가하는 것에 실패했을 것입니다. –

+0

여기에 더 많은 제약이 있습니까? 이와 같이 asm 명령에 지시문을 추가하는 것은 새로운 것이 아닙니다. 사람들은 인텔 스타일 어셈블러를 영원히 asm 명령어에 넣기 위해이 명령어를 사용 해왔다. –

+0

@David - 감사합니다. 나는 같은 줄로 생각했다. Alas, 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에 Jiong 왕에서왔다. 그것은 가스의 건축 요구 사항을 무시하고 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을 수정함으로써 잠재적 인 부작용을 원하지 않았기 때문에 Wang의 대답을하기로 결정했습니다.

그리고 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