Fonctionnement de ASM volatile ( ""::: "mémoire")

qu'est-ce que fondamentalement __asm__ __volatile__ () et quelle est la signification de "memory" pour l'architecture ARM?

38
demandé sur Tor Klingberg 2013-02-19 09:40:17

4 réponses

asm volatile("" ::: "memory");

crée une barrière de mémoire au niveau du compilateur forçant l'optimiseur à ne pas réordonner les accès de mémoire à travers la barrière.

par exemple, si vous avez besoin d'accéder à une adresse dans un ordre précis (probablement parce que cette zone de mémoire est en fait soutenue par un périphérique différent plutôt qu'une mémoire), vous devez être capable de le dire au compilateur sinon il se peut que cela optimise vos étapes pour des raisons d'efficacité.

supposons que dans ce scénario vous devez augmenter un valeur dans l'adresse, lire quelque chose et incrémenter une autre valeur dans une adresse adjacente.

int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        d[1] += 1;
        return r;
}

Problème de compilateur (gcc dans ce cas) peut réarranger votre accès mémoire pour obtenir de meilleures performances si vous le demandez (-O). Probablement conduisant à une séquence d'instructions comme ci-dessous:

00000000 <c>:
   0:   4603        mov r3, r0
   2:   c805        ldmia   r0, {r0, r2}
   4:   3001        adds    r0, #1
   6:   3201        adds    r2, #1
   8:   6018        str r0, [r3, #0]
   a:   6808        ldr r0, [r1, #0]
   c:   605a        str r2, [r3, #4]
   e:   4770        bx  lr

valeurs ci-Dessus concernant d[0] et d[1] sont chargés en même temps. Supposons que c'est quelque chose que vous voulez éviter, alors vous devez dire à compilateur de ne pas réorganiser les accès à la mémoire et qui est d'utiliser asm volatile("" ::: "memory").

int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        asm volatile("" ::: "memory");
        d[1] += 1;
        return r;
}

ainsi vous obtiendrez votre séquence d'instructions comme vous le souhaitez:

00000000 <c>:
   0:   6802        ldr r2, [r0, #0]
   2:   4603        mov r3, r0
   4:   3201        adds    r2, #1
   6:   6002        str r2, [r0, #0]
   8:   6808        ldr r0, [r1, #0]
   a:   685a        ldr r2, [r3, #4]
   c:   3201        adds    r2, #1
   e:   605a        str r2, [r3, #4]
  10:   4770        bx  lr
  12:   bf00        nop

il faut noter qu'il ne s'agit que de la barrière de mémoire de temps de compilation pour éviter que le compilateur ne réordonne les accès mémoire, car il ne met pas d'instructions de niveau de matériel supplémentaire pour vider les mémoires ou attendre que la charge ou les stocks soient remplis. Les CPU peuvent toujours réordonner les accès mémoire s'ils ont les capacités architecturales et les adresses mémoire sont sur normal Tapez au lieu de strongly ordered ou device ( ref).

57
répondu auselen 2014-03-31 12:45:23

cette séquence est une barrière de programmation d'accès à la mémoire du compilateur, tel que noté dans L'article cité par Udo. Celui - ci est spécifique au GCC-d'autres compilateurs ont d'autres façons de les décrire, certains avec des déclarations plus explicites (et moins ésotériques).

__asm__ est une extension de gcc permettant aux déclarations en langage assembleur d'être entrées imbriquées dans votre code C-utilisé ici pour sa propriété de pouvoir spécifier les effets secondaires qui empêchent le compilateur d'effectuer certains types d'optimisations (qui dans ce cas pourrait générer un code incorrect).

__volatile__ est nécessaire pour s'assurer que l' asm la déclaration elle-même n'est pas réordonnée avec d'autres accès volatiles (une garantie en langage C).

memory est une instruction pour GCC qui dit (en quelque sorte) que la séquence asm inline a des effets secondaires sur la mémoire globale, et donc pas seulement des effets sur les variables locales doivent être pris en compte.

17
répondu unixsmurf 2013-02-19 07:53:06

Le sens est expliqué ici:

http://en.wikipedia.org/wiki/Memory_ordering

fondamentalement, cela implique que le code d'assemblage sera exécuté là où vous l'attendez. Il dit au compilateur de ne pas réordonner les instructions autour de lui. C'est ce qui est codé avant ce morceau de code sera exécuté avant et ce qui est codé après sera exécuté après.

9
répondu Udo Klein 2013-02-19 07:17:05
static inline unsigned long arch_local_irq_save(void)
{
    unsigned long flags;

    asm volatile(
        "   mrs %0, cpsr    @ arch_local_irq_save\n"
        "   cpsid   i"      //disabled irq
        : "=r" (flags) : : "memory", "cc");
return flags;
}
-1
répondu leesagacious 2016-10-26 04:16:04