IL_000a: nop
IL_000b: call string [System.Console]System.Console::ReadLine()
IL_0010: pop
IL_0011: ret
} // end of method '
} // end of class '
Обратите внимание, что файл *.il
System.Runtime и System.Console), тогда вы обнаружили бы дополнительные директивы .assembly extern.Далее следует формальное определение сборки RoundTrip.dll
.module, .imagebase и т.д.).После документирования внешних ссылаемых сборок и определения текущей сборки находится определение типа Program
.class имеет различные атрибуты (многие из которых необязательны) вроде приведенного ниже атрибута extends, который указывает базовый класс для типа:.class private abstract auto ansi beforefieldinit '
extends [System.Runtime]System.Object
{ ... }
Основной объем кода CIL представляет реализацию стандартного конструктора класса и автоматически сгенерированного метода Main()
.method. После того, как эти члены были определены с использованием корректных директив и атрибутов, они реализуются с применением разнообразных кодов операций.Важно понимать, что при взаимодействии с типами .NET Core (такими как System.Console) в CIL
Main() в CIL:.method private hidebysig static void '
{
// Помечает этот метод как точку входа исполняемой сборки.
.entrypoint
.maxstack 8
IL_0000: ldstr "Hello CIL code!"
IL_0005: call void [System.Console]System.Console::WriteLine(string)
IL_000a: nop
IL_000b: call string [System.Console]System.Console::ReadLine()
IL_0010: pop IL_0011: ret
} // end of method '
Роль меток в коде CIL
Вы определенно заметили, что каждая строка в коде реализации предваряется лексемой в форме IL_X
IL_0000:, IL_0001: и т.д.). Такие лексемы называются ildasm.exe автоматически генерирует метки кода, которые следуют соглашению об именовании вида IL_XXXX:. Однако их можно заменить более описательными маркерами, например:.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
Nothing_1: nop
Load_String: ldstr "Hello CIL code!"
PrintToConsole: call void [System.Console]System.Console::WriteLine(string)
Nothing_2: nop
WaitFor_KeyPress: call string [System.Console]System.Console::ReadLine()
RemoveValueFromStack: pop
Leave_Function: ret
}
В сущности, большая часть меток кода совершенно не обязательна. Единственный случай, когда метки кода по-настоящему необходимы, связан с написанием кода CIL, в котором используются разнообразные конструкции ветвления или организации циклов, т.к. с помощью меток можно указывать, куда должен быть направлен поток логики. В текущем примере все автоматически сгенерированные метки кода можно удалить безо всяких последствий:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
nop
ldstr "Hello CIL code!"
call void [System.Console]System.Console::WriteLine(string)
nop