98 votes

Quelle est la différence entre le code natif, le code machine et le code assembleur ?

Je suis confus au sujet du code machine et du code natif. Quelle est la différence entre les deux ? Sont-ils identiques ou non, s'il vous plaît ?

140voto

Timwi Points 30896

Ces termes sont en effet un peu déroutants, car ils sont parfois utilisés de manière incohérente.

Code machine : C'est celui qui est le mieux défini. Il s'agit du code qui utilise les instructions du 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ù code machine (voir ci-dessus). Cependant, il est aussi parfois utilisé pour signifier code non géré (voir ci-dessous).

Code non géré et code géré : Non gérée fait référence au code écrit dans un langage de programmation tel que le C ou le C++, qui est compilé directement dans le code de l'entreprise. code machine . Il contraste avec code géré Il 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 le logiciel. La principale différence est que code géré "gère les ressources (principalement l'allocation de mémoire) à votre place en utilisant le ramassage des déchets et en gardant les références aux objets opaques. Code non géré est le genre de code qui vous oblige à allouer et désallouer manuellement la mémoire, ce qui provoque parfois des fuites de mémoire (lorsque vous oubliez de désallouer) et parfois des défauts de segmentation (lorsque vous désallouez trop tôt). Non gérée implique aussi généralement qu'il n'y a pas de vérification à l'exécution pour les erreurs courantes telles que le déréférencement des pointeurs nuls ou le dépassement des limites des tableaux.

À proprement parler, la plupart des langages à typage dynamique - tels que Perl, Python, PHP et Ruby - sont également code géré . Cependant, ils ne sont pas communément décrits comme tels, ce qui montre que code géré est en fait une sorte de terme marketing pour les très grands, sérieux et commerciaux environnements de programmation (.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 d'octet. Un site assembleur est un programme qui transforme ce code source en véritable code d'octet. Il ne s'agit pas d'un compilateur car la transformation est de 1 à 1. Cependant, le terme est ambigu quant au type de code d'octet utilisé : il peut être géré ou non. S'il est non géré, le code d'octet résultant est code machine . S'il est géré, il s'agit du code à octets utilisé en coulisse par un environnement virtuel tel que .NET. Le code géré (par exemple C#, Java) est compilé dans ce langage spécial de code à octets, qui, dans le cas de .NET, est appelé Langage intermédiaire commun (LIC) et en Java est appelé Octet-code Java . Le programmeur ordinaire n'a généralement pas besoin d'accéder à ce code ou d'écrire directement dans ce langage, mais lorsqu'il le fait, il y fait souvent référence en tant que code de montage parce qu'ils utilisent un assembleur pour le transformer en byte-code.

44voto

Hans Passant Points 475940

Ce que vous voyez lorsque vous utilisez Debug + Windows + Disassembly pour déboguer un programme C# est un bon guide pour ces termes. En voici une version annotée lorsque je compile un programme 'hello world' écrit en C# dans la configuration Release avec l'optimisation JIT activée :

        static void Main(string[] args) {
            Console.WriteLine("Hello world");
00000000 55                push        ebp                           ; save stack frame pointer
00000001 8B EC             mov         ebp,esp                       ; setup current frame
00000003 E8 30 BE 03 6F    call        6F03BE38                      ; Console.Out property getter
00000008 8B C8             mov         ecx,eax                       ; setup "this"
0000000a 8B 15 88 20 BD 02 mov         edx,dword ptr ds:[02BD2088h]  ; arg = "Hello world"
00000010 8B 01             mov         eax,dword ptr [ecx]           ; TextWriter reference
00000012 FF 90 D8 00 00 00 call        dword ptr [eax+000000D8h]     ; TextWriter.WriteLine()
00000018 5D                pop         ebp                           ; restore stack frame pointer
        }
00000019 C3                ret                                       ; done, return

Cliquez avec le bouton droit de la souris sur la fenêtre et cochez la case "Show Code Bytes" pour obtenir un affichage similaire.

La colonne de gauche est l'adresse du code machine. Sa valeur est truquée par le débogueur, le code est en fait situé ailleurs. Mais cela pourrait être n'importe où, selon l'emplacement sélectionné par le compilateur JIT, donc 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 que le CPU exécute. Le code machine, comme ici, est généralement affiché en hexadécimal. À titre d'exemple, 0x8B sélectionne l'instruction MOV, les octets supplémentaires sont là pour indiquer au CPU ce qui doit être déplacé. Notez également les deux variantes de l'instruction CALL, 0xE8 est l'appel direct, 0xFF est l'instruction d'appel indirect.

La troisième colonne est le code de montage . L'assemblage est un langage simple, conçu pour faciliter l'écriture du code machine. Il se compare à C# qui est compilé en IL. Le compilateur utilisé pour traduire le code assembleur est appelé "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 utilisés. Celle que vous voyez est celle qu'Intel et AMD utilisent. Dans le monde du logiciel libre, l'assemblage en 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 pour un PowerPC est très différent.

Ok, cela répond à deux des termes de votre question. "Code natif" est un terme flou, il n'est pas rare qu'il soit utilisé pour décrire du code dans un langage non géré. Il est peut-être instructif de voir quel type de code machine est généré par un compilateur C. Il s'agit de la version "hello world" en C :

int _tmain(int argc, _TCHAR* argv[])
{
00401010 55               push        ebp  
00401011 8B EC            mov         ebp,esp 
    printf("Hello world");
00401013 68 6C 6C 45 00   push        offset ___xt_z+128h (456C6Ch) 
00401018 E8 13 00 00 00   call        printf (401030h) 
0040101D 83 C4 04         add         esp,4 
    return 0;
00401020 33 C0            xor         eax,eax 
}
00401022 5D               pop         ebp  
00401023 C3               ret   

Je ne l'ai pas annoté, surtout parce qu'il est si similaire au code machine généré par le programme C#. L'appel à la fonction printf() est très différent de l'appel à Console.WriteLine() mais tout le reste est à peu près identique. Notez également que le débogueur génère maintenant l'adresse réelle du code machine et qu'il est un peu plus intelligent en ce qui concerne les symboles. Un effet secondaire de la génération d'informations de débogage après générer du 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 que celui-ci ait un aspect similaire. Les compilateurs C/C++ disposent de beaucoup plus de temps 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 y a très peu de différences entre le code machine généré à partir d'un langage géré par le compilateur JIT et le code machine généré par un compilateur de code natif. C'est la raison principale pour laquelle le langage C# peut être compétitif avec un compilateur de code natif. La seule véritable différence entre eux est constituée par les appels de fonctions de support. Beaucoup d'entre eux sont mis en œuvre dans le CLR. Et cela tourne principalement autour du garbage collector.

6voto

cHao Points 42294

Le code natif et le code machine sont la même chose - les octets réels que le CPU exécute.

Le code assembleur a deux significations : l'une est le code machine traduit en une forme plus lisible par l'homme (avec les octets des instructions traduits en mots mnémoniques courts comme "JMP" (qui "saute" à un autre endroit du code). L'autre est le bytecode IL (octets d'instructions que les compilateurs comme C# ou VB génèrent, qui finiront par être traduits en code machine, mais qui ne le sont pas encore) qui vit dans une DLL ou un EXE.

2voto

Henk Holterman Points 153608

Dans .NET, les assemblages contiennent Langue intermédiaire MS (MSIL, parfois CIL).
C'est comme un code machine de "haut niveau".

Lorsqu'il est chargé, MSIL est compilé par l'application Compilateur JIT en code natif (code machine Intel x86 ou x64).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X