Je suis confus à propos du code machine et du code natif dans le contexte des langages .NET.
Quelle est la différence entre eux? Sont-ils les mêmes?
.net
assembly
bytecode
machine-code
samaladeepak
la source
la source
Réponses:
Les termes sont en effet un peu déroutants, car ils sont parfois utilisés de manière incohérente.
Code machine: c'est le plus bien défini. C'est un code qui utilise les instructions de code octet que votre processeur (le morceau de métal physique qui fait le travail réel) comprend et exécute directement. Tout autre code doit être traduit ou transformé en code machine avant que votre machine puisse l'exécuter.
Code natif: ce terme est parfois utilisé dans les endroits où le code machine (voir ci-dessus) est utilisé . Cependant, il est également parfois utilisé pour désigner du code non managé (voir ci-dessous).
Code non managé et code managé: unmanaged code fait référence à un code écrit dans un langage de programmation tel que C ou C ++, qui est compilé directement dans le code de la machine . Il contraste avec le code managé , qui est écrit en C #, VB.NET, Java ou similaire, et exécuté dans un environnement virtuel (tel que .NET ou JavaVM) qui «simule» en quelque sorte un processeur dans un logiciel. La principale différence est que le code managé «gère» les ressources (principalement l'allocation de mémoire) pour vous en utilisant le ramasse-miettes et en gardant les références aux objets opaques. Code non géréest le type de code qui vous oblige à allouer et désallouer manuellement de la mémoire, provoquant parfois des fuites de mémoire (lorsque vous oubliez de désallouer) et parfois des erreurs de segmentation (lorsque vous désallouez trop tôt). Unmanaged implique également généralement qu'il n'y a pas de vérifications au moment de l'exécution pour les erreurs courantes telles que le déréférencement du pointeur nul ou le dépassement des limites du tableau.
À proprement parler, la plupart des langages typés dynamiquement - tels que Perl, Python, PHP et Ruby - sont également du code géré . Cependant, ils ne sont pas généralement décrits comme tels, ce qui montre que le code managé est en fait un terme marketing pour désigner les environnements de programmation commerciaux très importants et sérieux (.NET et Java).
Code d'assemblage: ce terme fait généralement référence au type de code source que les gens écrivent lorsqu'ils veulent vraiment écrire du code octet. Un assembleur est un programme qui transforme ce code source en véritable byte-code. Ce n'est pas un compilateur car la transformation est 1 vers 1. Cependant, le terme est ambigu quant au type d'octet-code utilisé: il peut être géré ou non. S'il n'est pas géré, l'octet-code résultant est le code machine . S'il est géré, il en résulte le code d'octet utilisé en arrière-plan par un environnement virtuel tel que .NET. Le code managé (par exemple C #, Java) est compilé dans ce langage spécial d'octet-code, qui dans le cas de .NET est appelé Common Intermediate Language (CIL) et en Java est appelé Java byte-code. Il est généralement peu nécessaire que le programmeur commun accède à ce code ou écrive directement dans ce langage, mais lorsque les gens le font, ils y font souvent référence en tant que code d'assemblage car ils utilisent un assembleur pour le transformer en byte-code.
la source
Ce que vous voyez lorsque vous utilisez Debug + Windows + Disassembly lors du débogage d'un programme C # est un bon guide pour ces termes. Voici une version annotée de celui-ci lorsque je compile un programme `` hello world '' écrit en C # dans la configuration Release avec l'optimisation JIT activée:
Cliquez avec le bouton droit sur la fenêtre et cochez "Afficher les octets de code" pour obtenir un affichage similaire.
La colonne de gauche correspond à l'adresse du code machine. Sa valeur est truquée par le débogueur, le code est en fait situé ailleurs. Mais cela peut être n'importe où, en fonction de l'emplacement sélectionné par le compilateur JIT, de sorte que le débogueur commence simplement à numéroter les adresses à partir de 0 au début de la méthode.
La deuxième colonne est le code machine . Les 1 et 0 réels exécutés par la CPU. Le code machine, comme ici, est généralement affiché en hexadécimal. Peut-être que 0x8B sélectionne l'instruction MOV, les octets supplémentaires sont là pour indiquer exactement au CPU ce qui doit être déplacé. Notez également les deux saveurs de l'instruction CALL, 0xE8 est l'appel direct, 0xFF est l'instruction d'appel indirect.
La troisième colonne est le code d'assemblage . L'assembly est un langage simple, conçu pour faciliter l'écriture de code machine. Il se compare à C # en cours de compilation en IL. Le compilateur utilisé pour traduire le code d'assembly est appelé un «assembleur». Vous avez probablement l'assembleur Microsoft sur votre machine, son nom d'exécutable est ml.exe, ml64.exe pour la version 64 bits. Il existe deux versions courantes des langages d'assemblage en cours d'utilisation. Celui que vous voyez est celui qu'utilisent Intel et AMD. Dans le monde open source, l'assemblage dans la notation AT&T est courant. La syntaxe du langage dépend fortement du type de CPU pour lequel il a été écrit, le langage d'assemblage d'un PowerPC est très différent.
D'accord, cela aborde deux des termes de votre question. «Code natif» est un terme flou, il n'est pas rarement utilisé pour décrire du code dans un langage non managé. Il est peut-être instructif de voir quel type de code machine est généré par un compilateur C. Voici la version «bonjour le monde» en C:
Je ne l'ai pas annoté, principalement parce qu'il est tellement similaire au code machine généré par le programme C #. L'appel de la fonction printf () est assez différent de l'appel de Console.WriteLine () mais tout le reste est à peu près identique. Notez également que le débogueur génère maintenant l'adresse de code machine réelle et qu'il est un peu plus intelligent sur les symboles. Un effet secondaire de la génération d'informations de débogage après la génération de code machine comme le font souvent les compilateurs non gérés. Je dois également mentionner que j'ai désactivé quelques options d'optimisation du code machine pour rendre le code machine similaire. Les compilateurs C / C ++ ont beaucoup plus de temps disponible pour optimiser le code, le résultat est souvent difficile à interpréter. Et très difficile à déboguer.
Le point clé ici est qu'il existe très peu de différences entre le code machine généré à partir d'un langage managé par le compilateur JIT et le code machine généré par un compilateur de code natif. C'est la principale raison pour laquelle le langage C # peut être compétitif avec un compilateur de code natif. La seule vraie différence entre eux réside dans les appels de fonction de support. Beaucoup d'entre eux sont mis en œuvre dans le CLR. Et cela tourne principalement autour du ramasse-miettes.
la source
Le code natif et le code machine sont la même chose - les octets réels exécutés par le CPU.
Le code d'assemblage a deux significations: l'une est le code machine traduit dans une forme plus lisible par l'homme (avec les octets des instructions traduits en de courts mnémoniques de type mot comme "JMP" (qui "saute" à un autre endroit du code). L'autre est le bytecode IL (octets d'instructions générés par des compilateurs comme C # ou VB, qui finiront par être traduits en code machine, mais ne le sont pas encore) qui se trouvent dans une DLL ou un EXE.
la source
Dans .NET, les assemblys contiennent du code MS Intermediate Language (MSIL, parfois CIL).
C'est comme un code machine «de haut niveau».
Une fois chargé, MSIL est compilé par le compilateur JIT en code natif (code machine Intel x86 ou x64).
la source