Compilation du MSIL en code natif
Avant d'être exécuté, le langage MSIL (Microsoft Intermediate Language) doit être converti par un compilateur JIT (Just-In-Time) .NET Framework en code natif, un code spécifique au processeur qui s'exécute sur la même architecture d'ordinateur que le compilateur JIT. Dans la mesure où le Common Language Runtime fournit un compilateur JIT pour chaque architecture de processeur qu'il prend en charge, les développeurs peuvent écrire un jeu d'instructions MSIL pouvant être traité par un compilateur JIT et exécuté sur des ordinateurs ayant des architectures différentes. Cependant, votre code managé s'exécutera sur un système d'exploitation spécifique uniquement s'il appelle des API natives spécifiques à une plate-forme ou une bibliothèque de classes spécifique à une plate-forme.
La compilation JIT tient compte du fait qu'une partie du code ne sera peut-être jamais appelée au moment de l'exécution. Au lieu de consacrer du temps et des ressources mémoire à la conversion de toutes les instructions MSIL d'un fichier exécutable portable (PE) en code natif, elle les convertit au fur et à mesure des besoins au moment de l'exécution et stocke le code natif obtenu afin qu'il soit accessible pour les appels ultérieurs. Le chargeur crée et attache un stub à chacune des méthodes d'un type lorsque le type est chargé. Dans l'appel initial à la méthode, le stub passe le contrôle au compilateur JIT, qui convertit le MSIL de cette méthode en code natif et modifie le stub afin de diriger l'exécution vers l'emplacement du code natif. Les appels suivants de la méthode traitée par le compilateur JIT passent directement au code natif qui a été généré précédemment, réduisant ainsi le temps nécessaire à la compilation en mode JIT et à l'exécution du code.
Le runtime fournit une autre mode de compilation appelé génération de code d'installation. La génération de code d'installation convertit le MSIL en code natif à l'instar du compilateur JIT standard, mais il convertit de plus grandes unités de code à la fois, en stockant le code natif obtenu pour qu'il soit utilisé lorsque l'assembly sera chargé et exécuté ultérieurement. Lorsque la génération de code d'installation est utilisée, l'assembly entier en cours d'installation est converti en code natif, en tenant compte des informations connues au sujet des autres assemblys déjà installés. Le fichier obtenu est chargé et démarre plus rapidement qu'il ne l'aurait fait s'il avait été converti en code natif par l'option JIT standard.
Dans le cadre de la compilation du MSIL en code natif, le code est soumis à un processus de vérification, sauf si un administrateur a établi une stratégie de sécurité qui autorise le code à se soustraire à ce processus. La vérification examine le MSIL et les métadonnées afin de déterminer si le code est de type sécurisé, ce qui signifie qu'il ne doit accéder qu'aux emplacements de mémoire autorisés. La sécurité de type permet d'isoler les objets les uns des autres et de les protéger par conséquent de toute altération accidentelle ou malveillante. Elle garantit également que les restrictions liées à la sécurité peuvent être appliquées au code de manière fiable.
Le runtime s'appuie sur le fait que les instructions suivantes sont vraies pour le code de type sécurisé vérifié :
une référence à un type qui est strictement compatible avec le type référencé ;
seules les opérations définies de façon appropriée sont appelées pour un objet ;
les identités sont conformes à ce qu'elles prétendent être.
Pendant le processus de vérification, le code MSIL est examiné en vue d'essayer de confirmer qu'il peut accéder aux emplacements de mémoire et appeler des méthodes uniquement par le biais de types correctement définis. Par exemple, le code n'autorise pas l'accès aux champs d'un objet d'une manière qui accepte le débordement de capacité des emplacements de mémoire. Par ailleurs, le processus de vérification inspecte le code MSIL afin de déterminer s'il a été généré correctement, car un code MSIL incorrect peut donner lieu à une violation des règles de sécurité des types. Le processus de vérification passe un jeu de code de type sécurisé et correctement défini, et ne passe que du code de ce type. Cependant, une partie du code de type sécurisé peut ne pas passer le test de vérification avec succès en raison des limitations du processus de vérification, et certains langages, de par leur design, ne produisent pas un code de type sécurisé vérifié. Si le code de type sécurisé est requis par la stratégie de sécurité et si le code ne passe pas le test de vérification avec succès, une exception est levée lorsque le code est exécuté.