Utilisation et conservation des registres dans un assembly inline
Section spécifique à Microsoft
En général, vous ne devez pas supposer qu'un registre aura une valeur donnée lorsqu'un bloc __asm
commence. La conservation des valeurs de registre n'est pas garantie d'un bloc __asm
à un autre. Si vous terminez un bloc de code incorporé et que vous en démarrez un autre, vous ne pouvez pas être sûr que les registres dans le second bloc conservent les valeurs du premier bloc. Un bloc __asm
hérite des valeurs de registre qui résultent du flux d'exécution normal.
Si vous utilisez la convention d'appel __fastcall
, le compilateur passe les arguments de fonction dans les registres plutôt que sur la pile. Cela peut poser des problèmes dans les fonctions avec des blocs __asm
, car une fonction n'a aucun moyen de déterminer quel paramètre figure dans quel registre. Si la fonction reçoit un paramètre dans EAX et qu'elle stocke immédiatement un autre élément dans EAX, le paramètre d'origine est perdu. En outre, vous devez conserver le registre ECX dans toute fonction déclarée avec __fastcall
.
Pour éviter ces conflits de registre, n'utilisez pas la convention __fastcall
pour les fonctions qui contiennent un bloc __asm
. Si vous spécifiez la convention __fastcall
globalement avec l'option du compilateur /Gr, déclarez chaque fonction contenant un bloc __asm
avec __cdecl
ou __stdcall
. (L’attribut __cdecl
indique au compilateur d’utiliser la convention d’appel C pour cette fonction.) Si vous ne compilez pas avec /Gr, évitez de déclarer la fonction avec l’attribut __fastcall
.
Lorsque vous utilisez __asm
pour écrire le langage assembleur dans des fonctions C/C++, vous n'avez pas besoin de conserver les registres EAX, EBX, ECX, EDX, ESI ou EDI. Par exemple, dans power2. Exemple C dans l’écriture de fonctions avec l’assembly inline, la power2
fonction ne conserve pas la valeur dans le registre EAX. Cependant, l'utilisation de ces registres affecte la qualité du code, car l'allocateur de registre ne peut pas les utiliser pour stocker des valeurs d'un bloc __asm
à un autre. Par ailleurs, en utilisant EBX, ESI ou EDI dans du code assembleur inline, vous forcez le compilateur à enregistrer et à restaurer ces registres dans le prologue et l'épilogue de la fonction.
Vous devez conserver d'autres registres que vous utilisez (par exemple DS, SS, SP, BP et les registres indicateurs) pour la portée du bloc __asm
. Vous devez conserver les registres ESP et EBP, à moins d'avoir une bonne raison de les modifier (pour changer de pile, par exemple). Consultez également l’optimisation de l’assembly inline.
Certains types SSE requièrent l'alignement de pile sur huit octets, ce qui force le compilateur à émettre du code d'alignement de pile dynamique. Pour pouvoir accéder aux variables locales et aux paramètres de fonction après l'alignement, le compilateur tient à jour deux pointeurs de frame. Si le compilateur effectue une omission de pointeur d’image (FPO), il utilise EBP et ESP. Si le compilateur n’effectue pas d’objet de stratégie de groupe, il utilise EBX et EBP. Pour garantir l'exécution correcte du code, ne modifiez pas EBX dans le code asm si la fonctionnalité requiert l'alignement de pile dynamique, car cela peut modifier le pointeur de frame. Déplacez les types alignés sur huit octets hors de la fonction ou évitez d'utiliser EBX.
Remarque
Si votre code assembleur inline modifie l'indicateur de direction à l'aide des instructions STD ou CLD, vous devez restaurer l'indicateur à sa valeur d'origine.
FIN de la section spécifique à Microsoft