2017-04-19 2 views
1

J'essaye d'assembler un fichier qui utilise l'instruction CRC d'ARM. L'assembleur produit une erreur Error: selected processor does not support 'crc32b w1,w0,w0'.Le GAS génère-t-il des instructions à partir de l'assemblage en ligne?

Des contrôles d'exécution sont en place, nous sommes donc en sécurité avec l'instruction. La technique fonctionne bien sur i686 et x86_64. Par exemple, je peux assembler un fichier qui utilise Intel CRC intrinsics ou SHA Intrinsics sans -mcrc ou -msha (et sur une machine sans les fonctionnalités).

Voici le cas de test:

$ 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); 
} 

Et voici le résultat:

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

Mise en place du code ASM dans un fichier source et la compilation avec différentes options est impossible, car CRC32B sera utilisé dans les fichiers d'en-tête C++, aussi.

Comment puis-je obtenir le GAS pour assembler l'instruction?


La configuration et les options de GCC sont la raison pour laquelle nous essayons de faire les choses de cette façon. L'utilisateur ne lit pas les manuels, donc ils n'ajouteront pas -march=armv8-a+crc+crypto -mtune=cortex-a53 à CFLAGS et CXXFLAGS.

En outre, les distributions sont compilées sur une machine "moins performante", nous voulons donc que les routines d'accélération matérielle soient disponibles. Lorsque la bibliothèque est fournie par une distribution comme Linaro, les deux chemins de code (CRC logiciel et CRC accéléré par le matériel) seront disponibles.


La machine est un LeMaker HiKey, qui est ARMv8/Aarch64. Il dispose d'un processeur A53 avec CRC et Crypto (CRC et Crypto est facultative dans l'architecture):

$ 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 n'a pas plus de l'habituel définit l'on attend d'être présent par défaut:

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

aide GCC -march=native ne fonctionne pas sur ARM:

$ g++ -march=native -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)' 
cc1: error: unknown value ‘native’ for -march 

Et 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 

version GCC:

$ gcc -v 
... 
gcc version 4.9.2 (Debian/Linaro 4.9.2-10) 

version GAZ:

$ as -v 
GNU assembler version 2.24 (aarch64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.24 
+1

Je n'ai pas un environnement pour le tester, mais il semble que ce que vous avez besoin est '.arch_extension name'. Peut-être ajouté directement à cette instruction ASM. Selon [docs] (https://sourceware.org/binutils/docs/as/ARM-Directives.html), cela vous permet * d'ajouter ou de supprimer des extensions de façon incrémentielle à l'architecture compilée pour *. A défaut, peut-être ajouter un '.arch name' comme un bit de 'bas niveau' de 'basic' asm? –

+0

Ou y a-t-il d'autres contraintes ici qui me manquent? L'ajout de directives aux instructions ASM comme ceci n'est pas nouveau. Les gens l'ont utilisé pour mettre l'assembleur de style Intel dans des instructions asm depuis toujours. –

+0

@David - Merci. J'ai pensé dans le même sens. Hélas, A-32, Aarch32 et Aarch64 ne sont pas IA32. J'ai essayé '.arch_extension' hier, mais cela a entraîné des erreurs. '.arch_extension' a besoin de Binutils 2.26 à partir de 2016. 2.26 supporte Aarch32 et Aarch64. Voir aussi [Erreur: pseudo-op: '.arch_extension'] (https://lists.linaro.org/pipermail/linaro-toolchain/2017-April/006112.html) dans la liste de diffusion Linaro Toolchain. – jww

Répondre

2

Cette réponse est venue de Wang Jiong sur le Binutils mailing list. Il contourne les exigences architecturales de gaz et joue bien avec 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 
} 

Le second commenté par le bloc de préprocesseur a été suggéré par Nick Clifton sur le Binutils mailing list.L'idée est que GCC génère du code en utilisant l'ISA basé sur -march=XXX, donc cela n'a pas d'importance si nous augmentons les capacités pour dépasser l'assembleur. Nous avons décidé d'aller avec la réponse de Wang parce que nous ne voulions pas que les effets secondaires potentiels modifient le .cpu.

Et la vérification avec GCC 4.8 et 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