Компиляция кода IL и ilasm

Последнее обновление: 23.05.2022

Для компиляции сборки из кода IL предназначена утилита ilasm. Данная утилита, как и ildasm, также устанавливается как пакет nuget. В данном случае нам надо установить пакет Microsoft.Netcore.Ilasm

Ilasm и компиляция кода Intermediate Language в сборку .NET

На Windows данная утилита устанавливается по пути C:\Users\[имя_пользователя]\.nuget\packages\microsoft.netcore.ilasm\6.0.0\runtimes\native\

Для компиляции сборки утилите ilasm передается путь к файлу с кодом IL

ilasm путь_к_файлу

Также мы можем передать утилите различные параметры. В частности, если нам надо создать файл exe, то передается флаг "/exe". А если надо создать файл dll, то передается флаг "/dll".

ilasm путь_к_файлу /dll

Первая программа на IL

Для примера можно декомпилировать готовую сборку в код IL. Но в данном случае попробуем определить файл с кодом IL с нуля. Для этого определим на жестком диске отдельную папку, например, C:/msil. И создадим в этой папке новый файл, который назовем helloapp.il

Ilasm и компиляция кода Intermediate Language в сборку .NET

Определим в этом файле следующий код:

.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

Компиляция кода IL в сборку

Для компиляции кода выше откроем командную строку/терминал и сначала с помощью команды 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:

компиляция кода Intermediate Language с помощью утилиты ilasm в программу на .NET

Определим в данном файле следующее содержимое:

{
  "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>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850