IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Conversion little vers big endian


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 23
    Points : 16
    Points
    16
    Par défaut Conversion little vers big endian
    J'ai besoin de réaliser une conversion d'un "long long unsigned int" stocké en little endian vers du big endian.

    J'ai développé plusieurs méthodes de conversion en C/C++, cependant les performances ne sont pas exceptionnelles.
    J'aimerai savoir si injecter de l'assembleur dans du C/C++ pourrait m'aider à augmenter les performances ?

    Merci

    PS : J’utilise la distribution MinGW.

  2. #2
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 951
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 951
    Points : 5 671
    Points
    5 671
    Par défaut
    Jai,
    Citation Envoyé par kriz31
    J'ai besoin de réaliser une conversion d'un "long long unsigned int" stocké en little endian vers du big endian.

    J'ai développé plusieurs méthodes de conversion en C/C++, cependant les performances ne sont pas exceptionnelles.
    J'aimerai savoir si injecter de l'assembleur dans du C/C++ pourrait m'aider à augmenter les performances ?

    Merci

    PS : J’utilise la distribution MinGW.
    Ça dépend évidemment de ton code en C.

    Comme j'ai égaré ma boule de cristal...

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    L'assembleur peut aider par des instructions spécifiques, comme les rotations qui ne sont a prori pas ou peu utilisé par les compilateurs, en tout cas, pas sous ordre du codeur.

  4. #4
    Membre confirmé Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Points : 567
    Points
    567
    Par défaut
    L'instruction bswap permet de faire ça, elle prend un registre 32 bits ou 64 bits comme opérande.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    Je me suis inspiré de codes sur internet et voici mes pauvres tentatives sachant que si ma façon de mesurer est bonne la plus rapide et la 1er.

    1)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #define SWAP_INT32(x) ( (((x)>>24) & 0x000000FFL) \
                          | (((x)>>8)  & 0x0000FF00L) \
                          | (((x)<<8)  & 0x00FF0000L) \
                          | (((x)<<24) & 0xFF000000L) )
     
    #define SWAP_INT64(x) (((long long unsigned int) \
                           ((unsigned int)SWAP_INT32((unsigned int)((x<<32) >> 32))) << 32) \
                           |(unsigned int)SWAP_INT32((unsigned int)(x>>32) ))
    2)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #define SWAP_INT64(x) ( (((x)>>56) & 0x00000000000000FFLL) \
                          | (((x)>>40) & 0x000000000000FF00LL) \
                          | (((x)>>24) & 0x0000000000FF0000LL) \
                          | (((x)>>8)  & 0x00000000FF000000LL) \
                          | (((x)<<8)  & 0x000000FF00000000LL) \
                          | (((x)<<24) & 0x0000FF0000000000LL) \
                          | (((x)<<40) & 0x00FF000000000000LL) \
                          | (((x)<<56) & 0xFF00000000000000LL) )
    3)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    void swap_int64(void* x)
    {
      ((unsigned char*)x)[0] = ((unsigned char*)x)[7];
      ((unsigned char*)x)[1] = ((unsigned char*)x)[6];
      ((unsigned char*)x)[2] = ((unsigned char*)x)[5];
      ((unsigned char*)x)[3] = ((unsigned char*)x)[4];
      ((unsigned char*)x)[4] = ((unsigned char*)x)[3];
      ((unsigned char*)x)[5] = ((unsigned char*)x)[2];
      ((unsigned char*)x)[6] = ((unsigned char*)x)[1];
      ((unsigned char*)x)[7] = ((unsigned char*)x)[0];
    }
     
    inline void inline_swap_int64(void* x)
    {
      ((unsigned char*)x)[0] = ((unsigned char*)x)[7];
      ((unsigned char*)x)[1] = ((unsigned char*)x)[6];
      ((unsigned char*)x)[2] = ((unsigned char*)x)[5];
      ((unsigned char*)x)[3] = ((unsigned char*)x)[4];
      ((unsigned char*)x)[4] = ((unsigned char*)x)[3];
      ((unsigned char*)x)[5] = ((unsigned char*)x)[2];
      ((unsigned char*)x)[6] = ((unsigned char*)x)[1];
      ((unsigned char*)x)[7] = ((unsigned char*)x)[0];
    }
    4)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #define bswap(cb){                             \
            register char   c;                      \
            c = ((unsigned char*)cb)[0]; ((unsigned char*)cb)[0] = ((unsigned char*)cb)[3]; ((unsigned char*)cb)[3] = c;    \
            c = ((unsigned char*)cb)[1]; ((unsigned char*)cb)[1] = ((unsigned char*)cb)[2]; ((unsigned char*)cb)[2] = c;    \
            c = ((unsigned char*)cb)[4]; ((unsigned char*)cb)[4] = ((unsigned char*)cb)[7]; ((unsigned char*)cb)[7] = c;    \
            c = ((unsigned char*)cb)[5]; ((unsigned char*)cb)[5] = ((unsigned char*)cb)[6]; ((unsigned char*)cb)[6] = c;    \
    }
    Je n'ai que de vieux souvenirs d'école du 68000, Si quelqu'un peut m'aider à réaliser ce petit bout de code assembleur sous MinGW... çà serait cool

  6. #6
    Membre expérimenté

    Inscrit en
    Mai 2002
    Messages
    720
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 720
    Points : 1 594
    Points
    1 594
    Par défaut
    Salut!

    D'un point de vue portabilité, il peut être mieux de se cantoner à du code C et utiliser sys/endian.h... Mais si les conversions sont effectivement le goulot d'étranglement pour le traitement des données, alors ok, essayons de voir ce qu'on peut faire

    Tout d'abord, l'algo 3 est faux... a <= b puis b <= a; ... ça n'inverse pas a et b...

    En mettant cet algo de côté, le plus lent est certainement 4 a cause des manipulations sur des octets seulement et tout ce qui va avec. 1 et 2 doivent être kiff kiff...

    Si ça ne suffit pas, dans machine/endian.h, tu as des macros en asm pour faire ces inversions de variables, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define __word_swap_int_var(x) \
    __extension__ ({ register __uint32_t __X = (x); \
       __asm ("rorl $16, %0" : "+r" (__X)); \
       __X; })
     
    #define __byte_swap_int_var(x) \
    __extension__ ({ register __uint32_t __X = (x); \
       __asm ("bswap %0" : "+r" (__X)); \
       __X; })
     
    #define __byte_swap_word_var(x) \
    __extension__ ({ register __uint16_t __X = (x); \
       __asm ("xchgb %h0, %b0" : "+q" (__X)); \
       __X; })
    A regarder

  7. #7
    Membre confirmé Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Points : 567
    Points
    567
    Par défaut
    Donc pour convertir une variable en 32 bits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mov eax, variable
    bswap eax
    Pour une variable 64 bits sur un processeur 64 bits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mov rax, variable
    bswap rax
    Pour du 64 bits sur un processeur 32 bits, je propose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    mov ecx, ebx
    mov edx, eax
     
    bswap ecx
    bswap edx
    (avec la variable à inverser dans EAX:EBX, le résultat est dans ECX:EDX)

    Même chose sans utiliser ECX:EDX, mais avec une instruction en plus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    xor eax, ebx
    xor ebx, eax
    xor eax, ebx
     
    bswap eax
    bswap ebx
    Edit : Si tu utilises GCC il faudra sûrement convertir en syntaxe AT&T mais ça ne devrait pas être compliqué.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    Mea culpa, Le code N°3 est carrement faux...
    J'ai une envie terrible de modifier mon post

    Les macros __word_swap_int_var, __byte_swap_int_var, byte_swap_word_var n'existe pas dans la distribution MinGW.

    Certaine personne conseille de copier le fichier endians.h de Cygwin dans le répertoire include de MinGW.

    Cependant j'ai inclus le code directement dans mon source de test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    #define __word_swap_int_var(x) \
    __extension__ ({ register unsigned int __X = (x); \
       __asm ("rorl $16, %0" : "+r" (__X)); \
       __X; })
     
    #define __byte_swap_int_var(x) \
    __extension__ ({ register unsigned int __X = (x); \
       __asm ("bswap %0" : "+r" (__X)); \
       __X; })
     
    #define __byte_swap_word_var(x) \
    __extension__ ({ register __uint16_t __X = (x); \
       __asm ("xchgb %h0, %b0" : "+q" (__X)); \
       __X; })
     
    #define SWAP_INT64_4(x) (((long long unsigned int) \
                          ((unsigned int)__byte_swap_int_var((unsigned int)((x<<32) >> 32))) << 32) \
                          |(unsigned int)__byte_swap_int_var((unsigned int)(x>>32) ))

    Pour info le Code N°2 est quasiment aussi lent que le N°4.
    Le code N°1 va deux fois plus vite que le N°2.

    Voici ma première fonction en assembleur x86

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    # swap_uint64.s
    .data
    .align 2
     
    .global _swap_uint64
    _swap_uint64:
      pushl %ebp  
      movl %esp, %ebp
     
      movl 12(%ebp), %eax
      movl 8(%ebp), %edx
     
      bswap %eax
      bswap %edx
     
      movl %ebp,%esp  
      popl %ebp
      ret
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    // swap_uint64.h
    #ifndef __SWAP_UINT64_H__
    #define __SWAP_UINT64_H__
     
    #ifdef __cplusplus
    extern "C"
    {
    #endif
     
    extern long long unsigned int swap_uint64(long long unsigned int llui);
     
    #ifdef __cplusplus
    }
    #endif
     
    #endif
    Qu'en pensez vous ?

    J'ai un gain de 60% par rapport à la meilleure macro (code N°1)
    Mais elle est moins performante que SWAP_INT64_4......

    Est-il possible d'améliorer encore les performances ?
    (J'utilise un processeur et un OS 32 Bits )

    Que pensez vous que je puisse gagner en transformant cette fonction en procédure ?

    Merci

  9. #9
    Membre confirmé Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Points : 567
    Points
    567
    Par défaut
    A mon avis ce serait plus performant de mettre les quelques instructions en assembleur inline que d'appeler une fonction en utilisant la pile et tout ça.
    Je crois que l'instruction "movl %ebp,%esp" à la fin ne sert à rien puisque ESP n'est pas modifié dans la fonction.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 26/12/2012, 11h19
  2. Conversion de little-endian à big-endian et inversement
    Par Le Farfadet Spatial dans le forum C++
    Réponses: 10
    Dernier message: 04/08/2011, 15h10
  3. Conversion Big Endian vers Little Endian
    Par tupac25 dans le forum Langage
    Réponses: 2
    Dernier message: 13/04/2010, 16h40
  4. Bibliothèque de conversion Little / Big endian ?
    Par BakaOnigiri dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 21/12/2009, 14h17
  5. [Débutant] probleme compatibilité mac pc little et big endian
    Par tang97 dans le forum MATLAB
    Réponses: 2
    Dernier message: 14/02/2009, 10h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo