Introduzione al
CLR/MSIL
Alfredo Paolillo e Marco Servetto
Vocabolario

IL:


Intermediate Language, Standard ECMA del 1997
MSIL:

Microsoft IL, Implementazione Microsoft di IL
Introduzione


Perché .NET
Ambiente di esecuzione

Common Language Runtime
Perché .NET



Difficile effettuare sviluppo omogeneo
Molto tempo viene dedicato a far comunicare i
vari “strati”
Serve un salto qualitativo per semplificare lo
scenario
Codici

Evoluzione
Codice nativo
 Codice interpretato
 Codice MSIL

Codice nativo
Sorgenti
Compilatore
Codice
nativo
(.EXE)
Output
Codice interpretato
Sorgenti
Interprete
Output
Codice MSIL
Sorgenti
Compilatore
.NET
Codice
MSIL
(Assembly)
.EXE/.DLL
Compilatore
JIT
Codice
nativo
Output
Codice MSIL
Sorgenti
Compilatore
.NET
Codice
MSIL
(Assembly)
.EXE/.DLL
Codice +
metadati
Compilatore
JIT
Codice
nativo
Output
Codice MSIL
Sorgenti
Compilatore
JIT
Ambiente di
Compilatore
esecuzione
.NET
.NET Runtime
Codice
nativo
Codice
MSIL
(Assembly)
.EXE/.DLL
Output
Motori JIT

Inizialmente previsti 4 motori:
Motore
Descrizione
Dove si trova
Attuale
implementazione
JIT
OptiJit
Codice più ottimizzato
Non implementato
FastJit
Esecuzione JIT più veloce
.NET Compact
Framework
Native
(Pre-Jit)
Compilazione preventiva, assembly
compilato salvato in GAC
NGEN.EXE
JIT – Just in Time Compiler



In teoria, come con Java, è possibile compilare
MSIL ed eseguirlo (interpretato) in qualsiasi
ambiente che supporti l’esecuzione
La compilazione di un’applicazione da un tipo di
codice assembly quale MSIL verso un codice
eseguibile sulla macchina nativa dovrebbe
appesantire le prestazioni dell’applicazione
È quello che succede?
JIT – Just in Time Compiler



Il codice non viene caricato tutto in memoria
il compilatore JIT compila solo il codice
necessario, quindi memorizza nella cache il
codice nativo compilato per riutilizzarlo
L’overhead è una lieve differenza che, nella
maggior parte dei casi, non verrà rilevata
JIT – Just in Time Compiler



Quando viene caricata una classe, il caricatore
aggiunge uno stub a ogni metodo della classe
La prima volta che viene chiamato il metodo, il
codice stub cede il controllo al compilatore JIT,
che compila MSIL nel codice nativo.
Lo stub viene quindi modificato per puntare al
codice nativo appena creato, affinché le chiamate
successive passino direttamente al codice nativo
Indipendenza dalla piattaforma

.NET è un’implementazione di CLI


CLI è uno standard ECMA


Common Language Infrastructure
ECMA-334, ECMA-335
Esistono già altre implementazioni di CLI:
SSCLI (Microsoft, per Windows, FreeBSD e
Macintosh)
 Mono (per Linux)
 DotGNU
 Intel OCL (Open CLI Library)
 …

Codice IL
Tutto questo assomiglia a qualcosa di già visto?
Forse Java?
 Ci sono delle differenze
 Un compilatore Java crea bytecode, che in fase
di esecuzione viene interpretato tramite JVM
 .NET crea un codice nativo
Codice IL




Un vantaggio rilevante offerto da .NET
Framework rispetto a Java e JVM è la scelta del
linguaggio di programmazione
JVM solo Java
.NET Multilinguaggio (VB.net, C#, J# etc…)
Vediamo un esempio di IL
Assembly
Modulo
(file PE)
Codice IL
Metadati
Manifest
Assembly
Metadati





Concetto chiave in .NET
Informazioni sui tipi di un assembly
Generati automaticamente dai compilatori
Estendibili da terze parti
Formato binario rappresentabile con XML:
XML Schema (XSD)
 Serializzazione e deserializzazione
oggetti a runtime in XML

Metadati

Descrizione di un assembly




Descrizione dei tipi


Identità: nome, versione, cultura [, pubblic key]
Tipi esportati
Assembly da cui dipende
Nome, visibilità, classe base, interfacce implementate
Attributi custom


Definiti dall’utente
Definiti dal compilatore
Codice IL

Proviamo adesso a scrivere e compilare dei
semplici programmi in C# e proviamo ad
analizzarli
Codice IL
Esempio 1
namespace testUno
{
public class esempioUno
{
public esempioUno()
{
}
static void Main(string[] args)
{
int primaVariabile = 0x1234;
int secondaVariabile = 0xabcdef;
}
}
}

Codice IL




Il file eseguibile è costituito da due parti:
 la prima è il codice MSIL, utilizzato per generare il
codice nativo
 la seconda è rappresentata dai metadati
Con un tool in dotazione con l’SDK possiamo
Diassemblare il file ottenuto dalla compilazione
Otterremo il seguente output
Tralasceremo comunque alcuni dettagli come il codice
del costruttore di classe
Codice IL
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size
13 (0xd)
.maxstack 1
.locals init (int32 V_0, int32 V_1)
IL_0000: ldc.i4 0x1234
IL_0005: stloc.0
IL_0006: ldc.i4 0xabcdef
IL_000b: stloc.1
IL_000c: ret
} // end of method esempioUno::Main
Codice IL – istruzioni principali






.entrypoint
 Specifies that this method is the entry point to the application (only one
such method is allowed).
.maxstack
 int32 specifies the maximum number of elements on the evaluation stack
during the execution of the method
.locals [init]
 Defines a set of local variables for this method.
ldc.i4:
 Description Push num of type int32 onto the stack as int32.
stloc.0:
 Description: Pop value from stack into local variable 0.
ret:
 Description: return from method, possibly returning a value
Codice IL – Metainformazioni
ScopeName : testUno.exe
MVID : {F01C8E38-E942-43D9-9D71-95D37789D357}
===========================================================
Global functions
------------------------------------------------------Global fields
------------------------------------------------------Global MemberRefs
------------------------------------------------------TypeDef #1
------------------------------------------------------TypDefName: testUno.esempioUno (02000002)
Flags : [Public] [AutoLayout] [Class] [AnsiClass] (00100001)
Extends : 01000001 [TypeRef] System.Object
Method #1
------------------------------------------------------MethodName: .ctor (06000001)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA
: 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
Method #2 [ENTRYPOINT]
------------------------------------------------------MethodName: Main (06000002)
Flags : [Private] [Static] [HideBySig] [ReuseSlot] (00000091)
RVA
: 0x00002064
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
ReturnType: Void
1 Arguments
Argument #1: SZArray String
1 Parameters
(1) ParamToken : (08000001) Name : args flags: [none] (00000000)
Codice IL – Metainformazioni
TypeRef #1 (01000001)
------------------------------------------------------Token:
0x01000001
ResolutionScope: 0x23000001
TypeRefName:
System.Object
MemberRef #1
------------------------------------------------------Member: (0a000002) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #2 (01000002)
------------------------------------------------------Token:
0x01000002
ResolutionScope: 0x23000001
TypeRefName:
System.Diagnostics.DebuggableAttribute
MemberRef #1
------------------------------------------------------Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
2 Arguments
Argument #1: Boolean
Argument #2: Boolean
Codice IL – Metainformazioni
Signature #1 (0x11000001)
------------------------------------------------------CallCnvntn: [LOCALSIG]
2 Arguments
Argument #1: I4
Argument #2: I4
Assembly
------------------------------------------------------Token: 0x20000001
Name : testUno
Public Key :
Hash Algorithm : 0x00008004
Major Version: 0x00000000
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
Flags : [SideBySideCompatible] (00000000)
CustomAttribute #1 (0c000001)
------------------------------------------------------CustomAttribute Type: 0a000001
CustomAttributeName: System.Diagnostics.DebuggableAttribute :: instance void .ctor(bool,bool)
Length: 6
Value : 01 00 00 01 00 00
>
<
ctor args: ( <can not decode> )
Codice IL – Metainformazioni
AssemblyRef #1
------------------------------------------------------Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Major Version: 0x00000001
Minor Version: 0x00000000
Build Number: 0x00001388
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
Codice IL
I metadati vengono organizzati in tabelle, in cui
fondamentalmente viene descritto ciò che il
codice definisce e a cui fa riferimento
Prestiamo attenzione a questa parte di codice:
CallCnvntn: [LOCALSIG]
2 Arguments
Argument #1: I4
Argument #2: I4
Codice C#
Proviamo adesso a compilare il seguente codice
FILE:esempioDueB

namespace testDue
{
public class esempioDueB
{
static void Main(string[] args)
{
esempioDueA variabile = new esempioDueA();
variabile.printString();
}
}
}
Codice C#
FILE: esempioDueA
using System;
namespace testDue
{
public class esempioDueA
{
public esempioDueA()
{
}
public void printString()
{
string s = "Hello!!!!";
Console.Write(s);
}
}
}
Codice IL
Disassembliamo:
A differenza di prima dovremo analizzare due
codici

Codice IL
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size
13 (0xd)
.maxstack 1
.locals init (class testDue.esempioDueA V_0)
IL_0000: newobj instance void testDue.esempioDueA::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void testDue.esempioDueA::printString()
IL_000c: ret
} // end of method esempioDueB::Main
Codice IL
.method public hidebysig instance void printString() cil managed
{
// Code size
13 (0xd)
.maxstack 1
.locals init (string V_0)
IL_0000: ldstr "Hello!!!!"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call
void [mscorlib]System.Console::Write(string)
IL_000c: ret
} // end of method esempioDueA::printString
Codice IL
Principali differenze rispetto al codice precedente:
 Newobj:
 Assembli format: newobjctor
 Description: allocate an uninitialized object or value type and call ctor
 Call:
 Assembli format: call method
 Description: Call method described by method
 Callvirt:
 Assembli format: callvirt method
 Description: Call a method associated with obj
Codice IL
Andiamo nuovamente a riesaminare le meta-informazioni:
Signature #2 (0x11000002) (EsempioDueB)
------------------------------------------------------CallCnvntn: [LOCALSIG]
1 Arguments
Argument #1: Class testDue.esempioDueA

Signature #1 (0x11000001) (EsempioDueA)
------------------------------------------------------CallCnvntn: [LOCALSIG]
1 Arguments
Argument #1: String
Codice IL – Metainformazioni
Method #2 (definizione del metodo invocato dalla call)
------------------------------------------------------MethodName: printString (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] (00000086)
RVA
: 0x00002064
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
..................
User Strings (costante)
------------------------------------------------------70000001 : ( 9) L"Hello!!!!”
Codice C#
Passaggio di parametri:
namespace testTre
{
public class esempioTreA
{
static void Main(string[] args)
{
string s = ("HELLO!!!!!!!!!!!!!!!!!!!!!!!!!!");
esempioTreB variabile = new esempioTreB();
variabile.printString(s);
}
}
}

Esempio C#
Using system;
public class esempioTreB
{
public esempioTreB()
{
}
public void printString(string s)
{
Console.Write(s);
}
}
Codice IL
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size
20 (0x14)
.maxstack 2
.locals init (string V_0, class testTre.esempioTreB V_1)
IL_0000: ldstr "HELLO!!!!!!!!!!!!!!!!!!!!!!!!!!"
IL_0005: stloc.0
IL_0006: newobj instance void testTre.esempioTreB::.ctor()
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: ldloc.0
IL_000e: callvirt instance void testTre.esempioTreB::printString(string)
IL_0013: ret
} // end of method esempioTreA::Main
Codice IL
.method public hidebysig instance void printString(string s) cil managed
{
// Code size
7 (0x7)
.maxstack 1
IL_0000: ldarg.1
IL_0001: call
void [mscorlib]System.Console::Write(string)
IL_0006: ret
} // end of method esempioTreB::printString
Codice IL
ldarg.1
 Assembli format: ldarg.1
 Description: Load argument 1 onto stack
Esistono anche delle varianti, ad esempio:
 ldarg num
 Assembli format: ldarg num
 Description: Load argument numbered num onto stack.

Codice IL – Metainformazioni
TypeDef #1
------------------------------------------------------TypDefName: testTre.esempioTreB (02000002)
Flags : [Public] [AutoLayout] [Class] [AnsiClass] (00100001)
Extends : 01000001 [TypeRef] System.Object
Method #1
------------------------------------------------------MethodName: .ctor (06000001)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA
: 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
Method #2
------------------------------------------------------MethodName: printString (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] (00000086)
RVA
: 0x00002064
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
1 Parameters
(1) ParamToken : (08000001) Name : s flags: [none] (00000000)
Codice IL – Metainformazioni
Signature #1 (0x11000001)
------------------------------------------------------CallCnvntn: [LOCALSIG]
2 Arguments
Argument #1: String
Argument #2: Class testTre.esempioTreB
Assenza di Signature #2
La classe su cui viene invocato il metodo printString non ha dichiarazioni locali
Garbage Collector

Gli oggetti vengono distrutti automaticamente
quando non sono più referenziati

Algoritmo Mark-and-Compact
Garbage Collector - fase 1: Mark
NextObjPtr
Root set
Oggetti “vivi”
Oggetti non raggiungibili
Spazio libero
Garbage Collector - fase 2:
Compact
Spazio recuperato
NextObjPtr
Root set
Oggetti “vivi”
Spazio libero
GC e distruzione deterministica

In alcuni casi serve un comportamento di
finalizzazione deterministica:
Riferimenti a oggetti non gestiti
 Utilizzo di risorse che devono essere rilasciate
appena termina il loro utilizzo



Non si possono usare i finalizzatori, che non
sono richiamabili direttamente
Implementare l’interfaccia IDisposable
Common Type System


Tutto è un oggetto
Due categorie di tipi:

Tipi reference (riferimento)


Tipi value (valore)


Allocati su heap gestito
Allocati su stack o in oggetti gestiti (reference)
Tutti i tipi value possono essere visti come tipi
reference

Boxing
Tipi value e reference in memoria
public struct Size {
public int height;
public int weight;
}
public class CSize {
public int height;
public int weight;
}
void Main() {
Size
v;
//
v.height = 100; //
CSize
r;
//
r.height = 100; //
r = new CSize(); //
r.height = 100; //
}
v.height
v.width
v istanza di Size
ok
r è un reference
illegale, r non assegnato
r fa riferimento a un CSize
ok, r inizializzata
height
width
r
Stack
Heap
Class CSize
Equivalenza e identità

Il confronto tra oggetti può essere:

di equivalenza


Object.Equals: oggetti con stesso tipo e uguale contenuto
di identità



Object.ReferenceEquals: stessa istanza o entrambi null
==: dipende dal tipo (come ReferenceEquals o altro)
Object.GetHashCode: rappresentazione univoca istanza
r1
r2=r1;
height
width
r2
Stack
Heap
Class CSize
Equivalenza e identità
“Teo”
19
a
b
c
“Ugo”
d
38
“Ugo”
38
.Equals(d)
==d
a
false
false
b
true
false
c
true
true
Boxing

I tipi value si possono sottoporre a “boxing” per
supportare le funzionalità tipiche degli oggetti
Un tipo value “boxed” è un clone indipendente
 Un tipo value “boxed” può tornare
ad essere value (unboxing)
 System.Object è il tipo universale

Boxing
Stack
i
int i = 123;
object o = i;
int k = (int)o;
Heap
123
int i = 123;
o
int
123
object o = i;
k
Boxing
123
int j = (int)o;
Unboxing
Conclusioni

Evoluzione della macchina virtuale


Si cerca di trovare il miglior compromesso tra
sicurezza, flessibilità e prestazioni
Non tutto è documentato

Scarsa documentazione per quanto riguarda i
metadati
Altre Informazioni

Dove posso ottenere maggiori informazioni
www.microsoft.com/msdn/italy/studenti
 www.ugidotnet.org
 www.gotdotnet.com
 www.ecma-international.org


Developer resources
Microsoft Visual Studio.NET
 Microsoft .NET Framework SDK
 Microsoft Developer Network

Scarica

ppt - DISI