GNU/Linux >> Tutoriels Linux >  >> Linux

Interdire les accès mémoire non alignés sur x86/x86_64

GCC et Clang ont tous deux intégré UndefinedBehaviorSanitizer. L'un de ces contrôles, alignment , peut être activé avec -fsanitize=alignment . Il émettra du code pour vérifier l'alignement du pointeur au moment de l'exécution et abandonnera si les pointeurs non alignés sont déréférencés.

Voir la documentation en ligne sur :

  • https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

C'est délicat et je ne l'ai pas fait personnellement, mais je pense que vous pouvez le faire de la manière suivante :

Les processeurs x86_64 (en particulier, j'ai vérifié Intel Corei7 mais je suppose que d'autres aussi) ont un compteur de performances MISALIGN_MEM_REF qui contre les références de mémoire mal alignées.

Donc, tout d'abord, vous pouvez exécuter votre programme et utiliser l'outil "perf" sous Linux pour obtenir un décompte du nombre d'accès mal alignés effectués par votre code.

Un hack plus délicat et intéressant serait d'écrire un module de noyau qui programme le compteur de performances pour générer une interruption en cas de débordement et le faire déborder du premier chargement/magasin non aligné. Répondez à cette interruption dans votre module de noyau mais en envoyant un signal à votre processus.

Cela transformera en fait le x86_64 en un cœur qui ne prend pas en charge l'accès non aligné.

Ce ne sera pas simple cependant - à côté de votre code, les bibliothèques système utilisent également des accès non alignés, il sera donc difficile de les séparer de votre propre code.


Je viens de lire la question L'accès mémoire non aligné provoque-t-il toujours des erreurs de bus ? qui a lié à l'article de Wikipedia Erreur de segmentation.

Dans l'article, il y a un merveilleux rappel des indicateurs de processeur Intel plutôt rares AC aka Alignment Check.

Et voici comment l'activer (à partir de l'exemple d'erreur de bus de Wikipedia, avec un bogue de zone rouge corrigé pour x86-64 System V, donc c'est sûr sur Linux et MacOS, et converti à partir de Basic asm, ce qui n'est jamais une bonne idée à l'intérieur des fonctions :vous souhaitez que les modifications apportées à AC soient ordonnées en fonction des accès à la mémoire.

#if defined(__GNUC__)
# if defined(__i386__)
    /* Enable Alignment Checking on x86 */
    __asm__("pushf\n orl $0x40000,(%%esp)\n popf" ::: "memory");
# elif defined(__x86_64__) 
     /* Enable Alignment Checking on x86_64 */
    __asm__("add $-128, %%rsp \n"    // skip past the red-zone, in case there is one and the compiler has local vars there.
            "pushf\n"
            "orl $0x40000,(%%rsp)\n"
            "popf \n"
            "sub $-128, %%rsp"       // and restore the stack pointer.
           ::: "memory");       // ordered wrt. other mem access
# endif
#endif

Une fois activé, il fonctionne beaucoup comme les paramètres d'alignement ARM dans /proc/cpu/alignment , voir la réponse Comment piéger les accès mémoire non alignés ? pour des exemples.

De plus, si vous utilisez GCC, je vous suggère d'activer -Wcast-align avertissements. Lors de la construction pour une cible avec des exigences d'alignement strictes (ARM par exemple), GCC signalera les emplacements qui pourraient conduire à un accès mémoire non aligné.

Mais notez que l'asm manuscrit de libc pour memcpy et d'autres fonctions fera toujours des accès non alignés, donc le réglage AC n'est souvent pas pratique sur x86 (y compris x86-64). GCC émettra parfois un asm qui rend les accès non alignés même si votre source ne le fait pas, par ex. comme optimisation pour copier ou mettre à zéro deux éléments de tableau ou membres de structure adjacents à la fois.


Linux
  1. Comment effacer le cache mémoire sous Linux

  2. Mesurer l'utilisation de RAM d'un programme ?

  3. Grep :Mémoire épuisée ?

  4. Surveillance et gestion de la mémoire

  5. Diagnostics de mémoire insuffisante de Windows

Qu'est-ce que la NVM (mémoire non volatile) ?

Comment effacer la mémoire d'échange sous Linux

Comment allouer de la mémoire alignée sur la taille de la page ?

Jenkins actif (sorti)

Utilisation de la mémoire de la commande TOP

Pourquoi les numéros d'appel du système Linux dans x86 et x86_64 sont-ils différents ?