Ortak Ara Dil - Common Intermediate Language

Eskiden Microsoft Intermediate Language ( MSIL ) veya Intermediate Language ( IL ) olarak adlandırılan Common Intermediate Language ( CIL ), Common Language Infrastructure (CLI) belirtiminde tanımlanan ara dil ikili komut kümesidir . CIL talimatları, Common Language Runtime gibi CLI uyumlu bir çalıştırma ortamı tarafından yürütülür . CLI'yi hedefleyen diller CIL'e derlenir. CIL, nesne yönelimli , yığın tabanlı bayt kodudur . Çalışma zamanları tipik olarak tam zamanında CIL talimatlarını yerel kodda derler .

CIL, .NET dillerinin beta sürümleri sırasında orijinal olarak Microsoft Orta Dili (MSIL) olarak biliniyordu. C # ve CLI'nin standardizasyonu nedeniyle , bayt kodu artık resmi olarak CIL olarak biliniyor. Windows Defender virüs tanımları, kendisiyle birlikte MSIL olarak derlenen ikili dosyalara başvurmaya devam etmektedir.

Genel bilgi

CLI programlama dillerinin derlenmesi sırasında , kaynak kodu platforma veya işlemciye özgü nesne kodu yerine CIL koduna çevrilir . CIL bir olduğu CPU gibi Ortak Dil Altyapı, destekleyen herhangi bir ortamda çalıştırılabilir ve platformdan bağımsız komut kümesi - .NET çalışma zamanı üzerinde Windows'un veya çapraz platform Mono çalışma zamanı. Teorik olarak bu, farklı platformlar ve CPU türleri için farklı yürütülebilir dosyalar dağıtma ihtiyacını ortadan kaldırır. CIL kodu, çalışma sırasında güvenlik açısından doğrulanır ve yerel olarak derlenen yürütülebilir dosyalardan daha iyi güvenlik ve güvenilirlik sağlar.

Yürütme süreci şuna benzer:

  1. Kaynak kodu CIL bayt koduna dönüştürülür ve bir CLI derlemesi oluşturulur.
  2. Bir CIL derlemesinin yürütülmesi üzerine, yerel kod üretmek için kodu çalışma zamanının JIT derleyicisinden geçirilir . Zamanın ilerisinde derleme de kullanılabilir, bu da bu adımı ortadan kaldırır, ancak yürütülebilir dosya taşınabilirliği pahasına.
  3. Bilgisayarın işlemcisi yerel kodu yürütür.

Talimatlar

CIL bayt kodu, aşağıdaki görev grupları için talimatlara sahiptir :

Hesaplamalı model

Ortak Ara Dil, nesne yönelimli ve yığın tabanlıdır ; bu, çoğu programlama dilinde olduğu gibi, komut parametrelerinin ve sonuçlarının birkaç yazmaç veya diğer bellek konumları yerine tek bir yığın üzerinde tutulduğu anlamına gelir .

Eax ve edx'in iki farklı genel amaçlı kaydı belirlediği x86 derleme dilinde iki sayı ekleyen kod :

add eax, edx

0'ın eax ve 1'in edx olduğu bir ara dilde (IL) kod :

ldloc.0    // push local variable 0 onto stack
ldloc.1    // push local variable 1 onto stack
add        // pop and add the top two stack items then push the result onto the stack
stloc.0    // pop and store the top stack item to local variable 0

İkinci örnekte, eax ve edx olmak üzere iki yazmacın değerleri ilk önce yığın üzerine itilir. Ekleme talimatı çağrıldığında, işlenenler "açılır" veya geri alınır ve sonuç yığın üzerinde "itilir" veya depolanır. Ortaya çıkan değer daha sonra yığından çıkarılır ve eax'ta saklanır.

Nesneye yönelik kavramlar

CIL, nesne yönelimli olacak şekilde tasarlanmıştır. Nesneler oluşturabilir, yöntemleri çağırabilir ve alanlar gibi diğer üye türlerini kullanabilirsiniz.

Her yöntemin (bazı istisnalar dışında) bir sınıfta bulunması gerekir. Bu statik yöntem de öyle:

.class public Foo {
    .method public static int32 Add(int32, int32) cil managed {
        .maxstack 2
        ldarg.0 // load the first argument;
        ldarg.1 // load the second argument;
        add     // add them;
        ret     // return the result;
    }
}

Add yöntemi, statik olarak bildirildiği için herhangi bir Foo örneğinin bildirilmesini gerektirmez ve daha sonra C # 'da şu şekilde kullanılabilir:

int r = Foo.Add(2, 3);    // 5

CIL'de şöyle görünecektir:

ldc.i4.2
ldc.i4.3
call int32 Foo::Add(int32, int32)
stloc.0

Örnek sınıfları

Bir örnek sınıfı, en az bir yapıcı ve bazı örnek üyeleri içerir. Aşağıdaki sınıf, bir Car nesnesinin eylemlerini temsil eden bir dizi yönteme sahiptir.

.class public Car {
    .method public specialname rtspecialname instance void .ctor(int32, int32) cil managed {
        /* Constructor */
    }

    .method public void Move(int32) cil managed { /* Omitting implementation */ }
    .method public void TurnRight() cil managed { /* Omitting implementation */ }
    .method public void TurnLeft() cil managed { /* Omitting implementation */ }
    .method public void Brake() cil managed { /* Omitting implementation */ }
}

Nesne oluşturma

C # sınıfında örnekler şu şekilde oluşturulur:

Car myCar = new Car(1, 4); 
Car yourCar = new Car(1, 3);

Ve bu ifadeler kabaca CIL'deki şu talimatlarla aynıdır:

ldc.i4.1
ldc.i4.4
newobj instance void Car::.ctor(int, int)
stloc.0    // myCar = new Car(1, 4);
ldc.i4.1
ldc.i4.3
newobj instance void Car::.ctor(int, int)
stloc.1    // yourCar = new Car(1, 3);

Örnek yöntemlerini çağırma

Örnek yöntemleri aşağıdaki gibi C # ile çağrılır:

myCar.Move(3);

CIL'de çağrıldığı gibi:

ldloc.0    // Load the object "myCar" on the stack
ldc.i4.3
call instance void Car::Move(int32)

Meta veriler

Ortak Dil Altyapı (CLI) olarak derlenmiş sınıfları hakkında bilgileri kaydeder meta veriler . Bileşen Nesne Modelindeki tür kitaplığı gibi , bu da uygulamaların montajdaki arabirimleri, sınıfları, türleri, yöntemleri ve alanları desteklemesini ve keşfetmesini sağlar. Bu tür meta verileri okuma sürecine " yansıma " denir .

Meta veriler, "öznitelikler" biçimindeki veriler olabilir. Nitelikler, Attribute sınıfı genişleterek özelleştirilebilir . Bu güçlü bir özelliktir. Sınıfın yaratıcısına, sınıfın tüketicilerinin uygulama alanına bağlı olarak çeşitli anlamlı şekillerde kullanabilecekleri ekstra bilgilerle süsleme yeteneği sağlar.

Misal

Aşağıda, CIL ile yazılmış temel bir Merhaba, Dünya programı bulunmaktadır. "Merhaba dünya!" Dizesini gösterecektir.

.assembly Hello {}
.assembly extern mscorlib {}
.method static void Main()
{
    .entrypoint
    .maxstack 1
    ldstr "Hello, world!"
    call void [mscorlib]System.Console::WriteLine(string)
    ret
}

Aşağıdaki kod, işlem kodlarının sayısında daha karmaşıktır.

Bu kod, Java bayt kodu hakkındaki makaledeki karşılık gelen kodla da karşılaştırılabilir .

static void Main(string[] args)
{
    for (int i = 2; i < 1000; i++)
    {
        for (int j = 2; j < i; j++)
        {
             if (i % j == 0)
                 goto outer;
        }
        Console.WriteLine(i);
        outer:;
    }
}

CIL sözdiziminde şuna benzer:

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack  2
    .locals init (int32 V_0,
                  int32 V_1)

              ldc.i4.2
              stloc.0
              br.s       IL_001f
    IL_0004:  ldc.i4.2
              stloc.1
              br.s       IL_0011
    IL_0008:  ldloc.0
              ldloc.1
              rem
              brfalse.s  IL_001b
              ldloc.1
              ldc.i4.1
              add
              stloc.1
    IL_0011:  ldloc.1
              ldloc.0
              blt.s      IL_0008
              ldloc.0
              call       void [mscorlib]System.Console::WriteLine(int32)
    IL_001b:  ldloc.0
              ldc.i4.1
              add
              stloc.0
    IL_001f:  ldloc.0
              ldc.i4     0x3e8
              blt.s      IL_0004
              ret
}

Bu, CIL'in sanal makine (VM) seviyesinin yakınında nasıl göründüğünün bir temsilidir . Derlendiğinde, yöntemler tablolarda saklanır ve talimatlar, bir Taşınabilir Yürütülebilir (PE) olan derlemenin içinde bayt olarak depolanır .

Nesil

Bir CIL derlemesi ve yönergeleri, bir derleyici veya yürütme ortamıyla birlikte gönderilen IL Assembler ( ILAsm ) adlı bir yardımcı program tarafından oluşturulur .

Montajlı CIL, IL Disassembler (ILDASM) kullanılarak tekrar koda ayrılabilir . CIL'i yüksek seviyeli bir dile (örn. C # veya Visual Basic ) dönüştüren .NET Reflector gibi başka araçlar da vardır . Bu, CIL'i tersine mühendislik için çok kolay bir hedef haline getirir. Bu özellik, Java bayt kodu ile paylaşılır . Bununla birlikte, kodu gizleyebilen ve bunu kodun kolayca okunamayacağı ancak yine de çalıştırılabilir olması için yapan araçlar vardır .

Yürütme

Tam zamanında derleme

Tam zamanında derleme (JIT), bayt kodunu CPU tarafından hemen çalıştırılabilir koda dönüştürmeyi içerir. Dönüştürme, programın yürütülmesi sırasında kademeli olarak gerçekleştirilir. JIT derlemesi, ortama özgü optimizasyon, çalışma zamanı tipi güvenliği ve montaj doğrulaması sağlar. Bunu başarmak için, JIT derleyicisi herhangi bir yasa dışı erişim için derleme meta verilerini inceler ve ihlalleri uygun şekilde ele alır.

Zamanın ilerisinde derleme

CLI uyumlu yürütme ortamları , çalışma zamanında JIT sürecini kaldırarak daha hızlı yürütülmesini sağlamak için bir derlemenin Zamanının Ötesinde derlemesi (AOT) yapma seçeneğiyle birlikte gelir .

In .NET Framework adı verilen özel bir alet var Özgün Görüntü Oluşturucu (NGEN) o gerçekleştirdiği AOT. AOT için farklı bir yaklaşım , .Net Core kodunun bir çalışma zamanına bağımlı olmaksızın tek bir yürütülebilir dosyada derlenmesine izin veren CoreRT'dir . In Mono aynı zamanda bir AOT yapmak için bir seçenek yoktur.

İşaretçi talimatları - C ++ / CLI

Java'nın bayt kodundan önemli bir fark, CIL'in, C / C ++ kodunu CIL'de derlemek için gereken veri / işlev işaretçileri manipülasyonu için yeterli olan ldind, stind, ldloca ve birçok çağrı talimatıyla birlikte gelmesidir.

class A {
   public: virtual void __stdcall meth() {}
};
void test_pointer_operations(int param) {
	int k = 0;
	int * ptr = &k;
	*ptr = 1;
	ptr = &param;
	*ptr = 2;
	A a;
	A * ptra = &a;
	ptra->meth();
}

CIL'deki ilgili kod şu şekilde oluşturulabilir:

.method assembly static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) 
        test_pointer_operations(int32 param) cil managed
{
  .vtentry 1 : 1
  // Code size       44 (0x2c)
  .maxstack  2
  .locals ([0] int32* ptr,
           [1] valuetype A* V_1,
           [2] valuetype A* a,
           [3] int32 k)
// k = 0;
  IL_0000:  ldc.i4.0 
  IL_0001:  stloc.3
// ptr = &k;
  IL_0002:  ldloca.s   k // load local's address instruction
  IL_0004:  stloc.0
// *ptr = 1;
  IL_0005:  ldloc.0
  IL_0006:  ldc.i4.1
  IL_0007:  stind.i4 // indirection instruction
// ptr = &param
  IL_0008:  ldarga.s   param // load parameter's address instruction
  IL_000a:  stloc.0
// *ptr = 2
  IL_000b:  ldloc.0
  IL_000c:  ldc.i4.2
  IL_000d:  stind.i4
// a = new A;
  IL_000e:  ldloca.s   a
  IL_0010:  call       valuetype A* modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) 'A.{ctor}'(valuetype A* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst))
  IL_0015:  pop
// ptra = &a;
  IL_0016:  ldloca.s   a
  IL_0018:  stloc.1
// ptra->meth();
  IL_0019:  ldloc.1
  IL_001a:  dup
  IL_001b:  ldind.i4 // reading the VMT for virtual call
  IL_001c:  ldind.i4
  IL_001d:  calli      unmanaged stdcall void modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall)(native int)
  IL_0022:  ret
} // end of method 'Global Functions'::test_pointer_operations

Ayrıca bakınız

Referanslar

daha fazla okuma

Dış bağlantılar