Condividi tramite


Processo di esecuzione gestita

Il processo di esecuzione gestita include i passaggi seguenti, discussi in dettaglio più avanti in questo argomento:

  1. Scelta di un compilatore.

    Per usufruire dei vantaggi di Common Language Runtime, è necessario utilizzare uno o più compilatori di linguaggio destinati alla fase di esecuzione.

  2. Compilazione in MSIL.

    Mediante la compilazione, il codice sorgente viene convertito in Microsoft Intermediate Language (MSIL) e vengono generati i metadati richiesti.

  3. Compilazione di MSIL in codice nativo.

    In fase di esecuzione, un compilatore JIT converte il MSIL in codice nativo. Durante questa compilazione, il codice viene sottoposto a un processo di verifica in cui il MSIL e i metadati vengono esaminati per determinare se il codice sia o meno indipendente dai tipi.

  4. Esecuzione del codice.

    Common Language Runtime fornisce l'infrastruttura che rende possibile l'esecuzione e i servizi che è possibile utilizzare durante l'esecuzione.

Scelta di un compilatore

Per usufruire dei vantaggi forniti da Common Language Runtime (CLR), è necessario utilizzare uno o più compilatori di linguaggio destinati al runtime, quali il compilatore Visual Basic, C#, Visual C++, F# o uno dei numerosi compilatori di terze parti, quale il compilatore Eiffel, Perl o COBOL.

Poiché si tratta di un ambiente di esecuzione multilinguaggio, Common Language Runtime supporta un'ampia gamma di tipi di dati e di funzionalità di linguaggio. In base al compilatore di linguaggio utilizzato verrà stabilito quali di queste funzionalità sono disponibili e possono essere utilizzate per progettare il codice. È ancora il compilatore, e non Common Language Runtime, a determinare la sintassi che è necessario che venga utilizzata dal codice. Affinché il componente possa essere completamente utilizzato da parte di componenti scritti in altri linguaggi, è necessario che i relativi tipi esportati espongano esclusivamente funzionalità di linguaggio incluse nella specifica Common Language Specification (CLS). È possibile utilizzare l'attributo CLSCompliantAttribute per assicurare che il codice sia conforme a CLS. Per ulteriori informazioni, vedere Scrittura di codice conforme a CLS.

Torna all'inizio

Compilazione in MSIL

Quando compila in codice gestito, il compilatore converte il codice sorgente in Microsoft Intermediate Language (MSIL), una serie di istruzioni indipendenti dalla CPU facilmente convertibile in codice nativo. MSIL comprende istruzioni per il caricamento, la memorizzazione, l'inizializzazione e il richiamo di metodi su oggetti, per le operazioni aritmetiche e logiche, il flusso di controllo, l'accesso diretto alla memoria, la gestione delle eccezioni e altre operazioni ancora. Prima di poter eseguire il codice, è necessario convertire MSIL in codice specifico della CPU, normalmente mediante un compilatore JIT. Poiché in Common Language Runtime sono forniti uno o più compilatori JIT per ogni architettura di computer supportata, su ciascuna di queste può essere compilata in modalità JIT ed eseguita la medesima serie di istruzioni MSIL.

Quando un compilatore genera codice MSIL, genera anche metadati. I metadati descrivono i tipi contenuti nel codice, inclusa la definizione di ciascun tipo, le firme dei membri di ciascun tipo, i membri a cui fa riferimento il codice e altri dati utilizzati in fase di esecuzione. Il codice MSIL e i metadati sono contenuti in un file eseguibile di tipo PE che è basato sul formato Microsoft PE pubblicato e COFF (Common Object File Format), storicamente utilizzato per il contenuto eseguibile, e ne rappresenta un'estensione. Grazie a questo formato di file, che supporta sia MSIL che codice nativo che metadati, il sistema operativo è in grado di riconoscere immagini in Common Language Runtime. La presenza di metadati nel file, insieme al codice MSIL, consente al codice di autodescriversi, per cui non vi è alcuna necessità di librerie di tipi o del linguaggio di definizione dell'interfaccia (IDL, Interface Definition Language). In base a Common Language Runtime, vengono individuati ed estratti dal file i metadati necessari durante l'esecuzione.

Torna all'inizio

Compilazione di MSIL in codice nativo

Per poter eseguire Microsoft Intermediate Language (MSIL), è necessario compilarlo in codice nativo utilizzando Common Language Runtime per l'architettura del computer di destinazione. In .NET Framework sono disponibili due strumenti per l'esecuzione di questa conversione:

Compilazione tramite il compilatore JIT

La compilazione JIT converte MSIL in codice nativo su richiesta durante l'esecuzione dell'applicazione, quando il contenuto di un assembly viene caricato ed eseguito. Poiché in Common Language Runtime viene fornito un compilatore JIT per ogni architettura di CPU supportata, gli sviluppatori possono scrivere una serie di assembly MSIL compilabili in modalità JIT ed eseguibili su computer con architetture diverse. Se, tuttavia, il codice gestito chiama API native specifiche della piattaforma o una libreria di classi specifica della piattaforma, potrà essere eseguito solo in tale sistema operativo.

La compilazione JIT prende in considerazione la possibilità che parte del codice non venga mai chiamata durante l'esecuzione. Anziché impiegare tempo e memoria per convertire tutto il codice MSIL in un file PE in codice nativo, viene convertito solo il codice MSIL necessario in fase di esecuzione e il codice nativo risultante viene archiviato in memoria affinché vi possano accedere le chiamate successive nel contesto di tale processo. In seguito al caricamento e all'inizializzazione del tipo, il caricatore crea e associa uno stub a ciascun metodo del tipo. Quando si chiama per la prima volta un metodo, lo stub passa il controllo al compilatore JIT che converte il codice MSIL per tale metodo in codice nativo e modifica lo stub in modo che punti direttamente al codice nativo generato. Le chiamate successive al metodo compilato tramite JIT vengono pertanto inviate direttamente al codice nativo.

Generazione di codice in fase di installazione mediante NGen.exe

Poiché il compilatore JIT converte il codice MSIL di un assembly in codice nativo quando vengono chiamati singoli metodi definiti in tale assembly, si verifica un calo delle prestazioni in fase di esecuzione. Nella maggior parte dei casi tale calo è accettabile. Un aspetto ancora più importante è che il codice generato dal compilatore JIT è associato al processo che ha attivato la compilazione e non può essere condiviso tra più processi. Per consentire la condivisione del codice generato tra più chiamate di un'applicazione o tra più processi che condividono un insieme di assembly, Common Language Runtime supporta una modalità di compilazione anticipata. Tale modalità di compilazione utilizza il Ngen.exe (generatore di immagini native) per convertire gli assembly MSIL in codice nativo in modo molto simile al compilatore JIT. Il funzionamento di Ngen.exe differisce da quello del compilatore JIT per i tre aspetti seguenti:

  • Converte il codice MSIL in codice nativo prima di eseguire l'applicazione anziché durante l'esecuzione.

  • Compila un intero assembly alla volta anziché un metodo alla volta.

  • Rende persistente il codice generato nella cache delle immagini native come un file su disco.

Verifica del codice

Durante la compilazione di MSIL in codice nativo, è necessario che il codice MSIL passi un processo di verifica, a meno che un amministratore non abbia stabilito criteri di sicurezza in base ai quali il codice può evitare la verifica. Durante la verifica vengono esaminati il codice MSIL e i metadati per determinare se il codice è indipendente dai tipi, ovvero se accede solo alle posizioni di memoria a cui è autorizzato ad accedere. L'indipendenza dai tipi permette di isolare gli oggetti gli uni dagli altri e consente di proteggerli da danneggiamenti accidentali o intenzionali. Tale requisito garantisce inoltre che le restrizioni di sicurezza vengano imposte sul codice in modo affidabile.

In Common Language Runtime si presuppone che per il codice indipendente dai tipi verificabile siano valide le seguenti affermazioni :

  • Un riferimento a un tipo è strettamente compatibile con il tipo a cui si fa riferimento.

  • Solo gli operatori definiti in modo appropriato vengono richiamati su un oggetto.

  • Le identità corrispondono effettivamente a ciò che rappresentano.

Durante il processo di verifica, il codice MSIL viene esaminato per confermare la possibilità di accedere alle posizioni di memoria e chiamare metodi solo tramite tipi definiti correttamente. Il codice, ad esempio, non può consentire l'accesso ai campi di un oggetto secondo modalità che consentono il sovraccarico di posizioni di memoria. Il codice MSIL viene inoltre esaminato per verificare che sia stato generato correttamente, in quanto codice MSIL non corretto può condurre a violazioni delle regole relative all'indipendenza dai tipi. Il processo di verifica può essere superato solo da un gruppo ben definito di codice indipendente dai tipi. È tuttavia possibile che parte del codice indipendente dai tipi non superi la verifica a causa di alcune limitazioni del processo di verifica e che, per motivi legati alla progettazione, alcuni linguaggi non generino codice verificabile come indipendente dai tipi. Se i criteri di sicurezza richiedono codice indipendente dai tipi ma il codice non supera la verifica, al momento dell'esecuzione verrà generata un'eccezione.

Torna all'inizio

Esecuzione del codice

Common Language Runtime fornisce l'infrastruttura che rende possibile l'esecuzione gestita e i servizi che è possibile utilizzare durante l'esecuzione. Prima di poter eseguire un metodo, è necessario compilarlo nel codice specifico del processore. Ogni metodo per il quale è stato generato codice MSIL viene compilato tramite JIT quando viene chiamato per la prima volta e quindi viene eseguito. Alla successiva esecuzione del metodo, viene eseguito il codice nativo compilato in modalità JIT esistente. Questo processo di compilazione tramite JIT e di esecuzione del codice viene ripetuto fino al completamento dell'esecuzione.

In fase di esecuzione, il codice gestito riceve servizi quali le operazioni di Garbage Collection, la sicurezza, l'interoperabilità con il codice non gestito, il supporto per il debug tra linguaggi e il supporto avanzato per la distribuzione e il controllo delle versioni.

In Microsoft Windows XP e Windows Vista il caricatore del sistema operativo consente di verificare la presenza di moduli gestiti esaminando un bit nell'intestazione COFF. Il bit inviato denota un modulo gestito. Se il caricatore rileva moduli gestiti, carica mscoree.dll. _CorValidateImage e _CorImageUnloading notificano al caricatore il caricamento e lo scaricamento delle immagini dei moduli gestiti. Tramite _CorValidateImage vengono eseguite le seguenti azioni:

  1. Verifica della validità del codice come codice gestito.

  2. Modifica del punto di ingresso nell'immagine in un punto di ingresso nel runtime.

Nelle versioni a 64 bit dei sistemi operativi Windows, _CorValidateImage modifica l'immagine presente in memoria trasformandone il formato da PE32 a PE32+.

Torna all'inizio

Vedere anche

Riferimenti

Ilasm.exe (assembler MSIL)

Concetti

Common Language Specification

Metadati e componenti auto-descrittivi

Distribuzione di .NET Framework e delle applicazioni

Assembly in Common Language Runtime

Domini applicazione

Host di runtime

Altre risorse

Cenni preliminari su .NET Framework

Sicurezza in .NET Framework

Interoperabilità con codice non gestito