Question

Cela fait longtemps que je n'ai pas codé d'assembleur de bras et je suis un peu rouillé sur les détails. Si j'appelle une fonction C de bras, je n'ai plus qu'à me soucier de la sauvegarde des fichiers r0-r3 et lr, n'est-ce pas?

Si la fonction C utilise d’autres registres, est-il responsable de les sauvegarder sur la pile et de les restaurer? En d'autres termes, le compilateur générerait du code pour le faire pour les fonctions C.

Par exemple, si j'utilise r10 dans une fonction assembleur, je n'ai pas besoin d'insérer sa valeur dans la pile ni dans la mémoire, et de la restaurer / la restaurer après un appel en C, est-ce que je

Ceci est pour arm-eabi-gcc 4.3.0.

Était-ce utile?

La solution

Cela dépend de la ABI de la plate-forme pour laquelle vous compilez. Sous Linux, il existe deux ABI ARM; l'ancien et le nouveau. Autant que je sache, le nouveau (EABI) est en fait le AAPCS d’ARM. Les définitions complètes d'EABI sont actuellement en ligne ici sur ARM centre d'informations .

De l'AAPCS, & # 167; 5.1. 1 :

  • r0-r3 sont les registres d'argument et de travail; r0-r1 sont également les registres de résultats
  • r4-r8 sont des registres de sauvegarde d’appel
  • r9 peut être un registre de sauvegarde d’appel ou non (sur certaines variantes de l’AAPCS, il s’agit d’un registre spécial)
  • r10-r11 sont des registres de sauvegarde d’appel
  • r12-r15 sont des registres spéciaux

Un registre de sauvegarde d'appelé doit être sauvegardé par l'appelé (par opposition à un registre de sauvegarde d'appelant, où l'appelant enregistre le registre); Ainsi, si il s’agit de l’ABI que vous utilisez, vous n’avez pas besoin de sauvegarder r10 avant d’appeler une autre fonction (l’autre fonction est responsable de sa sauvegarde).

Modifier : le compilateur que vous utilisez ne fait aucune différence. gcc en particulier peut être configuré pour plusieurs ABI, et il peut même être changé en ligne de commande. Examiner le code prologue / épilogue qu’il génère n’est pas très utile, étant donné qu’il est adapté à chaque fonction et , le compilateur peut utiliser un autre moyen de sauvegarder un registre (par exemple, en le sauvegardant au milieu d’un fichier). fonction).

Autres conseils

Pour additionner les informations manquantes sur les registres NEON:

De l'AAPCS , § 5.1.1 Registres centraux:

  • r0-r3 sont les registres d'argument et de travail; r0-r1 sont également les registres de résultats
  • r4-r8 sont des registres de sauvegarde d’appel
  • r9 peut être un registre de sauvegarde d’appel ou non (sur certaines variantes de l’AAPCS, il s’agit d’un registre spécial)
  • r10-r11 sont des registres de sauvegarde d’appel
  • r12-r15 sont des registres spéciaux

À partir de l'AAPCS, §5.1.2.1 Conventions d'utilisation du registre VFP:

  • s16 – s31 (d8 – d15, q4 – q7) doivent être conservés
  • s0 – s15 (d0 – d7, q0 – q3) et d16 – d31 (q8 – q15) ne doivent pas être préservés

Message original:
convention de ne pas appeler registres-à-enregistrer

Pour ARM 64 bits, A64 (d'après Standard Call Procedure pour l'architecture ARM 64 bits)

Il existe trente et un registres 64 bits à usage général (entiers) visibles par le jeu d'instructions A64; ceux-ci sont étiquetés r0-r30 . Dans un contexte 64 bits, ces registres sont généralement désignés par les noms x0-x30 ; dans un contexte 32 bits, les registres sont spécifiés à l'aide de w0-w30 . De plus, un registre de pointeur de pile, SP , peut être utilisé avec un nombre d'instructions limité.

  • SP Le pointeur de pile
  • r30 LR Le registre de liens
  • r29 Le pointeur de trame FP
  • r19… r28 Registres sauvegardés par les locataires
  • r18 le registre de la plate-forme, si nécessaire; sinon un registre temporaire.
  • r17 IP1 Le deuxième registre temporaire intra-appel de procédure (peut être utilisé par placage d’appel et code PLT); à d'autres moments peuvent être utilisés comme registre temporaire.
  • r16 IP0 Le premier registre de travail intra-procédure-appel (utilisable par appel facettes et code PLT); à d'autres moments peuvent être utilisés comme registre temporaire.
  • r9… r15 Registres temporaires
  • r8 Registre de résultats indirects
  • r0… r7 Registres de paramètres / résultats

Les huit premiers registres, r0-r7 , permettent de transmettre des valeurs d'argument à un sous-programme et de renvoyer les valeurs de résultat d'une fonction. Ils peuvent également être utilisés pour conserver des valeurs intermédiaires dans une routine (mais, en général, uniquement entre les appels de sous-routines).

Les registres r16 (IP0) et r17 (IP1) peuvent être utilisés par un éditeur de liens comme registre de travail entre une routine et tout sous-programme appelé. Ils peuvent également être utilisés dans une routine pour conserver des valeurs intermédiaires entre les appels de sous-routines.

Le rôle du registre r18 est spécifique à la plate-forme. Si une plate-forme ABI a besoin d'un registre à usage général dédié pour porter un état inter-procédural (par exemple, le contexte du thread), elle doit utiliser ce registre à cette fin. Si la plate-forme ABI n’a pas de telles exigences, elle doit utiliser r18 comme registre temporaire supplémentaire. La spécification ABI de la plate-forme doit documenter l'utilisation de ce registre.

SIMD

L’architecture ARM 64 bits comporte également trente-deux autres registres, v0-v31 , qui peuvent être utilisés par les opérations SIMD et à virgule flottante. Le nom précis du registre changera en fonction de la taille de l'accès.

Remarque: Contrairement à AArch32, dans AArch64, les vues 128 bits et 64 bits d'un registre SIMD et d'un registre à virgule flottante ne chevauchent pas plusieurs registres dans une vue plus étroite. q1 , d1 et s1 se rapportent tous à la même entrée dans la banque de registres.

Les huit premiers registres, v0-v7 , permettent de transmettre des valeurs d'argument dans un sous-programme et de renvoyer les valeurs de résultat d'une fonction. Ils peuvent également être utilisés pour conserver des valeurs intermédiaires dans une routine (mais, en général, uniquement entre les appels de sous-routines).

Les

registres v8-v15 doivent être conservés par un appelé lors d'appels de sous-programmes; les registres restants ( v0-v7, v16-v31 ) n'ont pas besoin d'être conservés (ou doivent être préservés par l'appelant). En outre, seuls les 64 bits inférieurs de chaque valeur stockée dans v8-v15 doivent être conservés. Il incombe à l'appelant de conserver des valeurs plus grandes.

Les réponses de CesarB et Pavel ont fourni des citations de l’AAPCS, mais les problèmes en suspens demeurent. Est-ce que l'appelé sauve r9? Qu'en est-il de R12? Qu'en est-il de R14? De plus, les réponses étaient très générales et non spécifiques à la chaîne d'outils arm-eabi comme demandé. Voici une approche pratique pour savoir quels registres sont appelés et lesquels ne le sont pas.

Le code C suivant contient un bloc d’assemblage inline, qui prétend modifier les registres r0-r12 et r14. Le compilateur générera le code pour sauvegarder les registres requis par l’ABI.

void foo() {
  asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
}

Utilisez la ligne de commande arm-eabi-gcc-4.7 -O2 -S -o - foo.c et ajoutez les commutateurs pour votre plate-forme (par exemple, -mcpu = arm7tdmi ). La commande imprimera le code d'assemblage généré sur STDOUT. Cela peut ressembler à quelque chose comme ça:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    bx  lr

Notez que le code généré par le compilateur enregistre et restaure r4-r11. Le compilateur n'enregistre pas r0-r3, r12. Le fait qu'il restaure r14 (alias lr) est purement accidentel, car je sais par expérience que le code de sortie peut également charger le lr sauvegardé dans r0 puis faire un "bx r0". au lieu de "bx lr". Soit en ajoutant -mcpu = arm7tdmi -mno-thumb-interwork ou en utilisant -mcpu = cortex-m4 -mthumb , nous obtenons un code d'assemblage légèrement différent ressemblant à ceci:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}

Encore une fois, les r4 à r11 sont sauvegardés et restaurés. Mais r14 (alias lr) n’est pas restauré.

Pour résumer:

  • r0-r3 ne sont pas enregistrés -
  • r4-r11 sont sauvegardés par un appel
  • r12 (alias ip) n'est pas enregistré -
  • r13 (alias sp) est sauvegardé par un appel
  • r14 (alias lr) n'est pas enregistré -
  • r15 (alias pc) est le compteur de programme et est défini sur la valeur de lr avant l'appel de fonction

Ceci vaut au moins pour les valeurs par défaut de arm-eabi-gcc. Certains commutateurs de ligne de commande (notamment le commutateur -mabi) peuvent influer sur les résultats.

Il existe également une différence au moins dans l’architecture Cortex M3 pour l’appel à une fonction et une interruption.

Si une interruption se produit, le transfert automatique de la pile à la pile R0-R3, R12, LR et PC est renvoyé automatiquement. Si vous utilisez d’autres registres dans la routine IRQ, vous devez les pousser / les insérer manuellement dans Stack.

Je ne pense pas que ces PUSH et POP automatiques sont conçus pour un appel de fonction (instruction de saut). Si la convention stipule que R0-R3 ne peut être utilisé que comme registre d'argument, de résultat ou de travail, il n'est donc pas nécessaire de les stocker avant l'appel de fonction car aucune valeur ne devrait être utilisée plus tard après le retour de la fonction. Mais comme dans une interruption, vous devez stocker tous les autres registres de la CPU si vous les utilisez dans votre fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top