IL assembly: Załadowanie zmiennych lokalnych + operatory

W poprzednim poście opisałem jak działa stos w IL. Wiemy, że jest on kluczowy dla wszelkich operacji. Jedną z ważniejszych instrukcji, wprowadzonych w tamtym poście jest ldc.i4. Służy ona do załadowania liczby 4 bajtowej na stos.
Oprócz niej, istnieje wiele innych instrukcji, które pełnią analogiczną rolę. Rozważmy następujący kod c#:

float floatNumber = 533.3f;
double doubleNumber = 5454.14;
string text = "text";
int[] array = new int[] {21, 3};

Console.WriteLine(floatNumber);
Console.WriteLine(doubleNumber);
Console.WriteLine(text);

Float zostanie załadowany za pomocą:
ldc.r4 533.3

Instrukcja analogiczna do wspomnianej ldc.i4. Cyfra „4” oznacza liczbę bajtów, a przedrostek „r” lub „i” kolejno real (zmiennoprzecinkowa) i integer (całkowita).

Dla double będzie to ldc.r8, ponieważ jest to liczba 8-bajtowa. String z kolei ma osobną instrukcję ldstr:

ldstr "text"

To jeszcze nie wszystko. W IL istnieje wiele skrótów. Oczywiście programistów c# zwykle takie szczegóły nie interesują. Ułatwia to jednak czytanie kodu IL, kiedy pracujemy nad jakąś optymalizacją albo gdy po prostu aplikacja nie działa poprawnie.

W celu zaprezentowania skrótów do powyższych instrukcji spójrzmy na:

int minusOne = -1;
int plusOne = 1;
bool falseVaue = false;
bool trueValue = true;

object objectNull = null;

Powyższe wartości maja specjalne instrukcje. Zamiast np. pisać ldc.i4 -1 mamy ldc.i4.m1. Podsumowując, powyższy kod wygeneruje kolejno:

•    ldc.i4.m1 – załadowanie -1

•    ldc.i4.1 – załadowanie +1

•    ldc.i4.0 – załadowanie false (Boolean)

•    ldc.i4.1 – załadowanie true (Boolean)

•    ldnull – załadowanie null

W dokumentacji znajdziemy wiele innych skrótów, ale są one analogiczne do powyższych i dość oczywiste.

Myślę, że przy okazji stosu, warto również wspomnień o:

•    pop – instrukcja zdejmuje element ze stosu

•    dup – instrukcja duplikujecie element znajdujący się na górze stosu.

Funkcja pop jest dość oczywista i po prostu usunie wartość ze stosu. Najprostszy kod, obrazujący pop to:

int a = 5;
a.ToString();
int b = 5;

Wywołanie ToString spowoduje umieszczenie wyniku na stosie. Nie jest on nigdzie używany, zatem należy go usunąć potem (przed int b=5) ze stosu:

ldc.i4.5
stloc.0
ldloca.s a
call instance string [mscorlib]System.Int32::ToString()
pop

Instrukcja dup z kolei ma na celu optymalizację. Bardzo często musimy mieć duplikat wartości na stosie. Na przykład, jeśli chcemy tą samą liczbę umieścić w zmiennej lokalnej i wykonać jakaś operacje na niej. Instrukcja stloc (umieszczenie wartości w zmiennej lokalnej) zdejmuje również wartość ze stosu, a wszelkie operacje operują wyłącznie na stosie.

W poprzednim wpisie pokazałem również instrukcje add. Oczywiście istnieje szereg innych operacji tzn.:

  • 1.    neg – negacja (!)
  • 2.    sub – odejmowanie
  • 3.    mul – mnożenie
  • 4.    div – dzielenie
  • 5.    rem – reszta z dzielenia
  • 6.    shl – przesuniecie o jeden bit w lewo
  • 7.    shr- analogicznie w prawo
  • 8.    operatory bitowe: and, or, xor, not

Jeśli mamy dwie wartości (a,b) na stosie, wykonanie odpowiedniej instrukcji umieści cyfrę 1 albo 0, w zależności od operatora i relacji argumentów. Dostępne instrukcje to: clt, cle, cgt, cge, ceq, cne.

Leave a Reply

Your email address will not be published.