Основы синтаксиса IL

Сборки и модули. Заголовок программы

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

Ключевыми элементами программы на IL являются сборки (assembly) и модули (module). Каждый модуль рассматривается как отдельный файл с кодом на IL. Сборка состоит из одного и более модулей.

Сборка всегда включает манифест, который содержит ряд данных:

  • Версию, имя, культуру и параметры безопасности

  • Список файлов, которые принадлежат сборке, а также криптографический хеш каждого файла

  • Типы, определенные в каждом файле, который используется сборкой

  • Цифровую подпись манифеста и публичный ключ, который используется для ее генерации (опционально)

Манифест един для всех модулей сборки и располагается в главном модуле сборки.

При определении программы на языке 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
}
.assembly HelloApp{}
.module HelloApp.dll

Заголовок может состоять из ряда функциональных блоков, основные из них:

  • .assembly: определяет параметры текущей сборки

  • .assembly extern: подключает внешние сборки

  • .file: определяет файлы, связанные с данной сборкой

  • .module: определение текущего модуля

  • .mresource: определяет ассоциированные со сборкой ресурсы

  • .module extern: подключает внешние модули

Подключение внешних сборок

Если программа использует какой-то уже имеющийся функционал других сборок, то эти сборки надо подключить с помощью команды

.assembly extern [название_сборки]

Например, выражение

.assembly extern System.Runtime{}

подключает в программу функционал сборки System.Runtime.dll. В частности, она содержит определения базовых типов, как string, int и т.д. В программе выше как раз используется тип string для определения строки для вывода на консоль.

И при подключении сборки для нее может определяться ряд параметров:

  • .ver: версия сборки в формате .ver Int32:Int32:Int32:Int32 (старшая версия, младшая версия, номер билда и ревизии). Например, в коде

    .assembly extern System.Runtime
    {
      .ver 6:0:0:0
    }
    

    указывается, что используется 6-я версия сборки (.net 6.0)

  • .publickey: публичный ключ для генерации криптографического хеш-кода сборки в формате publickey=(значение).

  • .publickeytoken: младшие 8 байт хеша SHA-1 публичного ключа. Например:

    .assembly extern System.Runtime
    {
      .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) 
      .ver 6:0:0:0
    }
    
  • .hash: значение хеша подключаемой сборки в формате .hash=(значение)

  • .culture код_культуры: языковая культура сборки. Код культуры соответствует формату IETF RFC1766: "язык-страна/регион", где язык представляет двухсимвольный код в нижнем регистре в формате ISO 639-1, а "страна/регион" - двухсимвольный код в верхнем регистре в формате ISO 3166

  • .custom: кастомный атрибут в формате .custom=(определение_атрибута)

Определение текущей сборки

После подключения внешних сборок идет определение текущей сборки. В примере выше:

.assembly HelloApp{}

Директива .assembly определяет манифест и указывает, к какой сборке принадлежит текщий модуль. После директивы .assembly идет название текущей сборки.

Далее внутри фигурных скобок идут параметры сборки. Они почти такие же, которые используются при подключении внешних сборок:

  • .ver: версия сборки

  • .publickey: публичный ключ для генерации криптографического хеш-кода сборки

  • .hash algorithm: алгоритм хеширования в формате .hash algorithm Int32

    По умолчанию следует применять алгоритм SHA-1, для этого передается значение 32772 (0x8004 - в шестнадцатиричном формате).

  • .culture код_культуры: языковая культура сборки.

  • .custom: кастомный атрибут

В примере выше никаких параметров сборки не определялось. Но их также можно задать:

.assembly MSILApp
{
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}

Модули

Сборка состоит из модулей. Модуль представляет отдельный файл, который содержит некоторый исполняемый код. Для определения модуля применяется директива .module, после которой указывается имя текущего файла:

.module HelloApp.dll

Остальные заголовочные директивы

Вкратце рассмотрим некоторые заголовки, которые также могут применяться. Как правило они передают значения для генерируемого PE-файла и не являются особенностью MSIL или .NET.

.cornflags

Директива .cornflags устанавливает поле CLI-заголовка выходного PE-файла. по умолчанию это значение должно равняться 1.

.corflags 0x00000001

.subsystem

Директива .subsystem определяет тип среды приложения с помощью сохранения специального значения в заголовке PE-файла. Теоретически здесь может использоваться любое 32-битное целочисленное значение, однако обычно применяются следующие значения: 2 для программ с графическим интерфейсом и 3 для консольных программ. Например:

.subsystem 0x0003       // WINDOWS_CUI

.imagebase

Директива .imagebase задает значение для заголовка imagebase в PE-файле. Если вкратце, этот заголовок устанавливает предпочтительный адрес в виртуальной памяти, по которому файл будет загружаться. Например:

.imagebase 0x10000000

Для DLL обычно это адрес 0x10000000, а для EXE - 0x00400000

.file alignment

Директива .file alignment задает значение для заголовка FileAlignment в PE-файле. Этот заголовок устанавливает значение в байтах, которое используется для выравнивания данных. Это значение должно быть равно 0x200. Например:

.file alignment 0x00000200

.stackreserve

Директива .stackreserve определяет объем выделяемого стека в байтах. Это значение должно быть равно 0x100000 (1Mb). Например:

.stackreserve 0x00100000
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850