Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

Далее следует формальное определение сборки

RoundTrip.dll
, описанное с применением разнообразных директив CIL (
.module
,
.imagebase
и т.д.).

После документирования внешних ссылаемых сборок и определения текущей сборки находится определение типа

Program
, созданное из операторов верхнего уровня. Обратите внимание, что директива
.class
имеет различные атрибуты (многие из которых необязательны) вроде приведенного ниже атрибута
extends
, который указывает базовый класс для типа:

.class private abstract auto ansi beforefieldinit '<Program>$'

extends [System.Runtime]System.Object

{ ... }

Основной

объем кода CIL представляет реализацию стандартного конструктора класса и автоматически сгенерированного метода
Main
, которые оба определены (частично) посредством директивы
.method
. После того, как эти члены были определены с использованием корректных директив и атрибутов, они реализуются с применением разнообразных кодов операций.

Важно понимать, что при взаимодействии с типами .NET Core (такими как System.Console) в CIL всегда необходимо использовать полностью заданное имя типа. Более того, полностью заданное имя типа всегда должно предваряться префиксом в форме дружественного имени сборки, где определен тип (в квадратных скобках). Взгляните на следующую реализацию метода

Main
в CIL:

.method private hidebysig static void '<Main>$'(string[] args) cil managed

{

// Помечает этот метод как точку входа исполняемой сборки.

.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 '<Program>$'::'<Main>$'

Роль меток в коде CIL

Вы определенно заметили, что каждая строка в коде реализации предваряется лексемой в форме

IL_X
XX: (например,
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

call string [System.Console]System.Console::ReadLine

pop

ret

}

Взаимодействие c CIL: модификация файла *.il

Теперь, когда вы имеете представление о том, из чего состоит базовый файл CIL, давайте завершим эксперимент с возвратным проектированием. Цель здесь довольно проста: изменить сообщение, которое выводится в окно консоли. Вы можете делать что-то большее, скажем, добавлять ссылки на сборки или создавать новые классы и методы, но мы ограничимся простым примером.

Чтобы внести изменение, вам понадобится модифицировать текущую реализацию операторов верхнего уровня, созданную в виде метода

<Main>$
. Отыщите этот метод в файле
*.il
и измените сообщение на
"Hello from altered CIL code!"
.

Фактически код CIL был модифицирован для соответствия следующему определению на языке С#:

static void Main(string[] args)

{

Console.WriteLine("Hello from altered CIL code!");

Console.ReadLine;

}

Компиляция кода CIL

Предшествующие версии .NET позволяли компилировать файлы

*.il
с применением утилиты ilasm.exe. В .NET Core положение дел изменилось. Для компиляции файлов
*.il
вы должны использовать тип проекта
Microsoft.NET.Sdk.IL
. На момент написания главы он все еще не был частью стандартного комплекта SDK.

Начните с создания нового каталога на своей машине. Создайте в этом каталоге файл

global.json
, который применяется к текущему каталогу и всем его подкаталогам. Он используется для определения версии комплекта SDK, которая будет задействована при запуске команд .NET Core CLI. Модифицируйте содержимое файла, как показано ниже:

{

"msbuild-sdks": {

"Microsoft.NET.Sdk.IL": "5.0.0-preview.1.20120.5"

}

Поделиться с друзьями: