Для компиляции сборки из кода IL предназначена утилита ilasm. Данная утилита, как и ildasm, также устанавливается как пакет nuget. В данном случае нам надо установить пакет Microsoft.Netcore.Ilasm
На Windows данная утилита устанавливается по пути C:\Users\[имя_пользователя]\.nuget\packages\microsoft.netcore.ilasm\6.0.0\runtimes\native\
Для компиляции сборки утилите ilasm передается путь к файлу с кодом IL
ilasm путь_к_файлу
Также мы можем передать утилите различные параметры. В частности, если нам надо создать файл exe, то передается флаг "/exe". А если надо создать файл dll, то передается флаг "/dll".
ilasm путь_к_файлу /dll
Для примера можно декомпилировать готовую сборку в код IL. Но в данном случае попробуем определить файл с кодом IL с нуля. Для этого определим на жестком диске отдельную папку, например, C:/msil. И создадим в этой папке новый файл, который назовем helloapp.il
Определим в этом файле следующий код:
.assembly extern System.Runtime { .ver 6:0:0:0 } .assembly extern System.Console { .ver 6:0:0:0 } .assembly HelloApp{} .module HelloApp.dll .class private auto Program { .method private static void main(string[] args) cil managed { .entrypoint ldstr "Hello, METANIT.COM!" call void [System.Console]System.Console::WriteLine(string) ret } }
Вкратце рассмотрим, что представляет этот код. Вначале в файле идут подключения других - внешних сборок, которые задействуются в текущей программе:
.assembly extern System.Runtime { .ver 6:0:0:0 } .assembly extern System.Console { .ver 6:0:0:0 }
Из сборки System.Runtime берется определение типа string, а из сборки System.Console - класс Console, который выводит строку на консоль
В данном случае предполагается, что мы будет использовать версию .NET 6, поэтому для каждой внешней сборки указаны соответствующие версии.
Затем идет определение текущей сборки
.assembly HelloApp{}
Далее идет определение текущего модуля
.module HelloApp.dll
Затем расположение определение главного класса модуля - класса Program
.class private auto Program { //........... }
Далее идет входная точка в программу - метод main
.method private static void main(string[] args) cil managed { .entrypoint ldstr "Hello, METANIT.COM!" call void [System.Console]System.Console::WriteLine(string) ret }
Метод main использует два атрибута: атрибут cil указывает, что метод содержит стандартный код MSIL, а атрибут managed указывает, что метод содержит управляемый код (код, управляемый CRL)
Первая строка метода указывает, что это будет входная точка в программу:
.entrypoint
Метод main содержит три инструкции: ldstr, call и ret. Инструкция ldstr помещает в стек ссылку на объект, который представляет строковый литерал "Hello, METANIT.COM!".
Функция call вызывает метод System.Console::WriteLine, передавая ему строку в качестве аргумента.
И последняя инструкция - ret выполняет возврат из метода main
Для компиляции кода выше откроем командную строку/терминал и сначала с помощью команды cd перейдем к каталогу, где располагается файл с кодом IL. И затем передадим утилите ilasm имя данного файла:
C:\Users\eugen>cd C:\msil C:\msil>C:\Users\eugen\.nuget\packages\microsoft.netcore.ilasm\6.0.0\runtimes\native\ilasm helloapp.il /dll Microsoft (R) .NET IL Assembler. Version 6.0.0 Copyright (c) Microsoft Corporation. All rights reserved. Assembling 'helloapp.il' to DLL --> 'helloapp.dll' Source file is UTF-8 Assembled method Program::<Main>$ Assembled method Program::.ctor Creating PE file Emitting classes: Class 1: Program Emitting fields and methods: Global Class 1 Methods: 1; Emitting events and properties: Global Class 1 Writing PE file Operation completed successfully C:\msil>
После выполнения данной команды с текущей папке будет сгенерирован файл сборки с расширением dll (в моем случае файл helloapp.dll)
Теперь возникает вопрос, а как запустить данный файл? Для запуска нам потребуется еще один файл. Итак, создадим в папке, где находится скомпилированная сборка, еще один файл, который назовем [имя_файла_сборки].runtimeconfig.json. Например, в моем случае файл сборки называется helloapp.dll, соответственно файл конфига будет называться helloapp.runtimeconfig.json:
Определим в данном файле следующее содержимое:
{ "runtimeOptions": { "tfm": "net6.0", "framework": { "name": "Microsoft.NETCore.App", "version": "6.0.0" } } }
В данном случае предполагается, что мы используем .NET 6.
И в конце запустим сборку на выполнение в командной строке/терминале с помощью dotnet-cli:
C:\msil>dotnet helloapp.dll Hello, METANIT.COM! C:\msil>