[The Old New Thing] Puis-je utiliser ma pile à ma guise?

Sous Windows, la pile passe de grandes adresses à des adresses plus petites. Parfois, il est déterminé architecturalement, et parfois ce n'est qu'un accord accepté. La valeur du pointeur de pile (registre de processeur) est un pointeur sur la valeur en haut de la pile. Et les valeurs situées plus profondément sur la pile, respectivement, sont situées à de grandes adresses. Mais qu'advient-il des données situées à des adresses plus petites que le pointeur de pile?



Les conventions pour certaines architectures (mais pas toutes) définissent la zone rouge, qui est la zone de mémoire sous le pointeur de pile, mais qui est toujours valide pour une utilisation par l'application.



Pour Windows, la taille de la zone rouge varie en fonction de l'architecture matérielle et est souvent nulle.


L'architectureTaille de la zone rouge
x860 octets
x640 octets
Itanium16 octets *
Alpha AXP0 octets
MIPS320 octets
Powerpc232 octets **
ARM328 octets
ARM6416 octets

* La plate-forme Itanium mérite d'être signalée: une zone rouge est située au-dessus du pointeur de pile , et non en dessous.
** Dans le cas de PowerPC, la zone rouge est un effet secondaire de l'accord d'appel .


Toute mémoire située derrière la zone rouge (en bas de la pile) est considérée comme volatile et peut être modifiée par le système d'exploitation à tout moment.


Mais sérieusement, pourquoi le système d'exploitation se soucie-t-il de ce que je fais avec ma pile? Je veux dire, c'est ma pile! Le système d'exploitation ne me dit pas quoi faire de la mémoire que VirtualAlloc via VirtualAlloc . Qu'est-ce qui rend la pile différente de toute autre mémoire?


Considérez le code suivant pour la plate - forme x86 :


  MOV [esp-4], eax ;  eax    MOV ecx, [esp-4] ;     ecx CMP ecx, eax ;  ? JNZ panic ; N:  -  

Explication du commentaire de l'instruction JNZ

La convention de codage d'assemblage indique que les commentaires des instructions de branchement doivent décrire le résultat si la branchement est terminé. Dans l'exemple ci-dessus, l'instruction CMP pose la question «Sont-ils les mêmes?». Et l'instruction JNZ saute si elles ne sont pas égales. Ainsi, le commentaire commence par «N:», ce qui signifie que la transition sera terminée si la réponse à la question précédente est «Non», et le reste du commentaire décrit la situation lorsque la transition est effectuée.


Convention de codage de l'assembleur?

Oui, nous avons une convention de codage pour l'assembleur.


Est-il possible qu'une transition conditionnelle soit mise en œuvre?


Puisqu'il n'y a pas de zone rouge sur x86, la mémoire avec des décalages négatifs par rapport au pointeur de pile peut être écrasée à tout moment. Par conséquent, pour le code ci-dessus, la transition vers l'étiquette de panic est possible.


Le débogueur peut utiliser la mémoire derrière la zone rouge comme un endroit pratique pour stocker ses données. Par exemple, si vous utilisez la commande .call , le débogueur effectuera un appel imbriqué sur la même pile et utilisera probablement une partie de cet espace de pile pour enregistrer les registres afin qu'ils puissent être restaurés après le retour de la fonction appelée. Par conséquent, toutes les données stockées en dehors de la zone rouge seront détruites.


Même en fonctionnement normal, le système d'exploitation peut à tout moment écraser les données en dehors de la zone rouge. Voici, par exemple, comment cela peut se produire:


Supposons que votre thread exécute son intervalle de temps juste après avoir enregistré les données derrière la zone rouge. Pendant que votre thread attend de reprendre l'exécution, le gestionnaire de mémoire retire temporairement une page physique de votre code. Au final, votre thread reprend le contrôle et le gestionnaire de mémoire essaie de permuter la page en code. Oh non, une erreur d'E / S se produit pendant la pagination! Le système d'exploitation pousse le cadre d'exception pour STATUS_IN_PAGE_ERROR sur la pile, ce qui entraîne une corruption des données que vous avez enregistrée derrière la zone rouge.


Le système d'exploitation distribue cette exception. Il accède au gestionnaire d'exceptions vectorielles ( VEH ), qui est une autre partie de votre programme. Le gestionnaire a été installé spécifiquement pour gérer des situations exceptionnelles résultant du lancement possible de votre programme directement à partir d'un CD-ROM ou d'un réseau FS peu fiable. Le programme affiche une demande dans laquelle il demande à l'utilisateur de réinsérer le CD et propose de réessayer. Si l'utilisateur indique ce qui doit être répété, le gestionnaire d'exceptions vectorielles renvoie EXCEPTION_CONTINUE_EXECUTION et le système d'exploitation redémarre l'instruction sur laquelle l'exception s'est produite.


Cette fois, le redémarrage réussit car le CD-ROM est présent (et lu) et le code peut être pompé avec succès dans la mémoire. L'instruction suivante est exécutée, qui charge la valeur en dehors de la zone rouge dans le ecx . Mais ce n'est pas la même valeur qui a été enregistrée par l'instruction précédente, car l'exception STATUS_IN_PAGE_ERROR écrase. La comparaison indique que les données sont différentes et nous passons à l'étiquette de panic .


Si vous souhaitez enregistrer les données sur la pile, placez-les correctement: réduisez d'abord le pointeur de la pile, puis enregistrez la valeur dans la partie valide de la pile. Ne cachez pas de données derrière la zone rouge, cette mémoire peut être modifiée à tout moment à votre insu.

Source: https://habr.com/ru/post/fr435814/


All Articles