Question

Je passe en revue MSIL et constate qu'il y a beaucoup de nop instructions. L'article de MSDN indique qu'elles ne font rien et qu'elles sont utilisées pour remplir de l'espace si le code d'opération est corrigé. Ils sont beaucoup plus utilisés dans les versions de débogage que dans les versions de versions. Je sais que ce type d’instruction est utilisé dans les langages d’assemblage pour s’assurer qu’un opcode correspond à une limite de mot, mais pourquoi est-il nécessaire dans MSIL?

Était-ce utile?

La solution

Les NOP ont plusieurs objectifs:

  • Ils permettent au débogueur de placer un point d'arrêt sur une ligne même s'il est combiné avec d'autres dans le code généré.
  • Il permet au chargeur de corriger un saut avec un décalage cible de taille différente.
  • Cela permet à un bloc de code d'être aligné sur une limite particulière, ce qui peut être utile pour la mise en cache.
  • Il permet la liaison incrémentielle pour écraser des morceaux de code avec un appel vers une nouvelle section sans avoir à se soucier de la taille globale de la fonction qui change.

Autres conseils

Voici comment les nops sont utilisés par le débogage:

Les compilateurs de langage (C #, VB, etc.) utilisent Nops pour définir des points de séquence implicites. Celles-ci indiquent au compilateur JIT où s'assurer que les instructions machine peuvent être mappées aux instructions IL.

Entrée de blog de Rick Byer sur DebuggingModes.IgnoreSymbolStoreSequencePoints , explique quelques détails.

C # place également Nops après les instructions d'appel afin que l'emplacement du site de retour dans la source soit l'appel sortant plutôt que la ligne qui suit l'appel.

Il fournit une opportunité pour les marqueurs basés sur la ligne (par exemple, les points d'arrêt) dans le code où une version validée n'en émettrait aucun.

Cela peut également accélérer l'exécution du code lors de l'optimisation pour des processeurs ou des architectures spécifiques:

Les processeurs utilisent depuis longtemps plusieurs pipelines qui fonctionnent à peu près en parallèle, de sorte que deux instructions indépendantes peuvent être remplacées en même temps. Sur un processeur simple avec deux pipelines, le premier peut prendre en charge toutes les instructions, tandis que le second ne prend en charge qu'un sous-ensemble. De plus, il y a des blocages entre les pipelines quand il faut attendre le résultat d'une instruction précédente qui n'est pas encore terminée.

Dans ces circonstances, un nop dédié peut forcer la prochaine instruction dans un pipeline spécifique (le premier ou non le premier), et améliorer le couplage des instructions suivantes de sorte que le coût du < em> nop est plus qu’amorti.

Mec! No-op est génial! C'est une instruction qui ne fait que consommer du temps. Dans les périodes sombres, vous l'utiliseriez pour effectuer des micro-ajustements de la synchronisation dans les boucles critiques ou, plus important encore, pour compléter le code à modification automatique.

Dans un processeur pour lequel j'ai travaillé récemment (pendant quatre ans), NOP était utilisé pour s'assurer que l'opération précédente était terminée avant le début de l'opération suivante. Par exemple:

valeur de charge à enregistrer (prend 8 cycles) nop 8 ajouter 1 pour vous inscrire

Cela garantissait que le registre avait la valeur correcte avant l'opération d'ajout.

Une autre utilisation consistait à renseigner des unités d’exécution, telles que les vecteurs d’interruption qui devaient avoir une certaine taille (32 octets) car l’adresse de vector0 était, par exemple, de 0, celle du vecteur 1 0x20, etc., de sorte que le compilateur insère des NOP. si nécessaire.

L’une de leurs utilisations classiques est que votre débogueur puisse toujours associer une ligne de code source à une instruction IL.

Ils pourraient les utiliser pour prendre en charge modifier-continuer lors du débogage. Il fournit au débogueur l’espace nécessaire pour remplacer l’ancien code par du nouveau sans modifier les décalages, etc.

Nop est essentiel dans la charge utile des exploits de débordement de tampon.

Comme Ddaa l’a dit, nops vous permet de comptabiliser les écarts dans la pile. Ainsi, lorsque vous écrasez l’adresse de retour, il saute sur le nop sled (plusieurs nops dans une rangée), puis frappe correctement le code exécutable, plutôt que sauter à un octet dans l'instruction qui n'est pas le début.

50 ans trop tard mais bon.

Les NOP sont utiles si vous saisissez le code de l'assembly à la main. Si vous deviez supprimer du code, vous pourriez supprimer les anciens opcodes.

De la même façon, vous pouvez insérer un nouveau code en écrasant un opcode et en sautant ailleurs. Là, vous mettez les opcodes écrasés et insérez votre nouveau code. Lorsque vous êtes prêt, vous reculez.

Parfois, vous deviez utiliser les outils disponibles. Dans certains cas, il s’agissait d’un éditeur de code de machine très basique.

De nos jours, avec les compilateurs, les techniques n’ont plus aucun sens.

Dans la scène du cracking logiciel, une méthode classique pour déverrouiller une application consiste à patcher avec un NOP la ligne qui vérifie la clé, l’enregistrement ou la période, ou autre, afin de ne rien faire et de continuer simplement à démarrer l’application comme si: il est enregistré.

J'ai également vu des codes NOP dans le code se modifier eux-mêmes pour masquer son rôle en tant qu'espace réservé (très ancienne protection contre la copie).

Une utilisation peu orthodoxe est NOP-Slides , utilisé dans débordement de la mémoire tampon.

Ils permettent à l’éditeur de liens de remplacer une instruction plus longue (généralement un saut en longueur) par une instruction plus courte (un saut court). Le NOP occupe plus de place - le code ne peut pas être déplacé car cela empêcherait les autres sauts de fonctionner. Cela se produit au moment de la liaison, le compilateur ne peut donc pas savoir si un saut long ou court serait approprié.

Du moins, c'est l'une de leurs utilisations traditionnelles.

Ceci n'est pas une réponse à votre question précise, mais vous pouviez utiliser un NOP pour remplir un emplacement du délai de branchement , si vous ne parvenez pas à le remplir avec une instruction utile.

Les compilateurs .NET alignent-ils la sortie MSIL? J'imagine que cela pourrait être utile pour accélérer l'accès à l'IL ... De plus, si j'ai bien compris, il est conçu pour être portable et des accès alignés sont nécessaires sur d'autres plates-formes matérielles.

Le premier assemblage que j'ai appris était SPARC; je connais donc bien le créneau de délai de branche, si vous ne pouvez pas le remplir avec une autre instruction, généralement l'instruction que vous allez placer au-dessus de l'instruction de branche ou incrémenter un compteur de boucles , vous utilisez un NOP.

Je ne suis pas familier avec la fissuration, mais je pense qu'il est courant d'écraser la pile à l'aide de NOP afin que vous n'ayez pas à calculer exactement le début de votre fonction malveillante.

J’ai utilisé les NOP pour ajuster automatiquement la latence accumulée après la saisie d’un ISR. Très pratique pour clouer le chronomètre à fond.

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