Общий промежуточный язык
Эта статья нуждается в дополнительных ссылок для проверки . ( ноябрь 2017 г. ) |
Common Intermediate Language ( CIL ), ранее называвшийся Microsoft Intermediate Language ( MSIL ) или Intermediate Language ( IL ), [1] — это набор двоичных команд промежуточного языка , определенный в спецификации Common Language Infrastructure (CLI). [2] Инструкции CIL выполняются CIL-совместимой средой выполнения, такой как Common Language Runtime . Языки, ориентированные на CLI, компилируются в CIL. CIL — это объектно-ориентированный байт на основе стека -код . Среды выполнения обычно по принципу «точно в срок» компилируют CIL-инструкции в собственный код .
Первоначально CIL был известен как Microsoft Intermediate Language (MSIL) во время бета-выпусков языков .NET. Благодаря стандартизации C# и CLI байт-код теперь официально известен как CIL. [3] В определениях вирусов Защитника Windows двоичные файлы, скомпилированные с его помощью, продолжают называться MSIL. [4]
Общая информация [ править ]
Во время компиляции языков программирования CLI исходный код преобразуется в код CIL, а не в объектный код, специфичный для платформы или процессора . CIL — это независимый от процессора и платформы набор инструкций, который может выполняться в любой среде, поддерживающей Common Language Infrastructure, например, в среде выполнения .NET в Windows или в кроссплатформенной среде выполнения Mono . Теоретически это избавляет от необходимости распространять разные исполняемые файлы для разных платформ и типов процессоров. Код CIL проверяется на безопасность во время выполнения, обеспечивая лучшую безопасность и надежность, чем исполняемые файлы, скомпилированные в собственном коде. [5] [6]
Процесс выполнения выглядит следующим образом:
- Исходный код преобразуется в байт-код CIL и сборка CLI . создается
- При выполнении сборки CIL ее код передается через JIT-компилятор среды выполнения для создания собственного кода. Также можно использовать предварительную компиляцию, которая исключает этот шаг, но за счет переносимости исполняемого файла.
- Процессор компьютера выполняет собственный код.
Инструкция [ править ]
Байт-код CIL содержит инструкции для следующих групп задач:
- Загрузите и сохраните
- Арифметика
- Преобразование типов
- Создание и манипулирование объектами
- Управление стеком операндов (push/pop)
- Передача управления (ветвление)
- Вызов метода и возврат
- Выброс исключений
- Параллелизм на основе монитора
- Манипулирование указателями данных и функций, необходимое для C++/CLI и небезопасного кода C#.
Вычислительная модель [ править ]
Common Intermediate Language является объектно-ориентированным и основанным на стеке , что означает, что параметры и результаты инструкций хранятся в одном стеке, а не в нескольких регистрах или других местах памяти, как в большинстве языков программирования .
Код, добавляющий два числа на языке ассемблера x86 , где eax и edx указывают два разных регистра общего назначения :
добавить eax , edx
Код на промежуточном языке (IL), где 0 — eax, а 1 — edx:
лдлок . 0 // помещаем локальную переменную 0 в стек
ldloc . 1 // помещаем локальную переменную 1 в стек
add // извлекаем и добавляем два верхних элемента стека, затем помещаем результат в стек
stloc . 0 // извлекаем и сохраняем верхний элемент стека в локальную переменную 0
В последнем примере значения двух регистров, eax и edx, сначала помещаются в стек. Когда вызывается инструкция добавления, операнды «извлекаются» или извлекаются, а результат «помещается» или сохраняется в стеке. Полученное значение затем извлекается из стека и сохраняется в eax.
Объектно-ориентированные концепции [ править ]
CIL спроектирован как объектно-ориентированный. Вы можете создавать объекты, вызывать методы и использовать другие типы членов, например поля.
Каждый метод должен (за некоторыми исключениями) находиться в классе. То же самое делает этот статический метод:
. класс общественный Foo {
. метод public static int32 Add ( int32 , int32 ) cil Managed {
. maxstack 2
ldarg . 0 // загружаем первый аргумент;
лдарг . 1 // загружаем второй аргумент;
добавить // добавить их;
ret // возвращаем результат;
}
}
Метод Add не требует объявления какого-либо экземпляра Foo, поскольку он объявлен как статический, и затем его можно использовать в C# следующим образом:
int r = Фу . Добавить ( 2 , 3 ); // 5
В CIL это будет выглядеть так:
ООО . я4 . 2
ЖК . я4 . 3
вызовите int32 Foo :: Добавить ( int32 , int32 )
stloc . 0
Классы экземпляров [ править ]
Класс экземпляра содержит по крайней мере один конструктор и несколько членов экземпляра . Следующий класс имеет набор методов, представляющих действия объекта Car.
. класса общественный автомобиль {
. метод public Specialname rtspecialname экземпляр void . ctor ( int32 , int32 ) cil Managed {
/* Конструктор */
}
. метод public void Move ( int32 ) cil Managed { /* Опуская реализацию */ }
. метод public void TurnRight () cil Managed { /* Опуская реализацию */ }
. метод public void TurnLeft () cil Managed { /* Опуская реализацию */ }
. метод public void Brake () cil Managed { /* Пропуск реализации */ }
}
Создание объектов [ править ]
В C# экземпляры классов создаются следующим образом:
Автомобиль myCar = новый автомобиль ( 1 , 4 );
Автомобиль yourCar = новый автомобиль ( 1 , 3 );
И эти утверждения примерно такие же, как и эти инструкции в CIL:
ООО . я4 . 1
ЖК . я4 . 4
newobj экземпляра void Car ::. ctor ( int , int )
stloc . 0 // myCar = новый автомобиль(1, 4);
ООО . я4 . 1
ЖК . я4 . 3
newobj экземпляра void Car ::. ctor ( int , int )
stloc . 1 // ваша машина = новая машина (1, 3);
Вызов методов экземпляра [ править ]
Методы экземпляра в C# вызываются следующим образом:
моя машина . Двигаться ( 3 );
Как вызывается в CIL:
лдлок . 0 // Загрузите объект «myCar» в стек
ldc . я4 . 3
вызова экземпляра void Car :: Move ( int32 )
Метаданные [ править ]
Common Language Infrastructure (CLI) записывает информацию о скомпилированных классах в виде метаданных . Подобно библиотеке типов в объектной модели компонентов , это позволяет приложениям поддерживать и обнаруживать интерфейсы, классы, типы, методы и поля в сборке. Процесс чтения таких метаданных называется « отражением ».
Метаданные могут представлять собой данные в форме «атрибутов». Атрибуты можно настроить, расширив Attribute
сорт. Это мощная функция. Это дает создателю класса возможность дополнить его дополнительной информацией, которую потребители класса могут использовать различными значимыми способами, в зависимости от предметной области приложения.
Пример [ править ]
Ниже приведен базовый текст «Hello, World!» программа , написанная на ассемблере CIL. Он отобразит строку «Привет, мир!».
. сборка Привет {}
. сборка extern mscorlib {}
. метод static void Main ()
{
. входная точка
. maxstack 1
ldstr "Привет, мир!"
вызовите void [ mscorlib ] System . Консоль :: WriteLine ( строка )
ret
}
Следующий код более сложен по количеству кодов операций.
Этот код также можно сравнить с соответствующим кодом в статье про байт-код Java .
static void Main ( string [] args )
{
for ( int i = 2 ; i < 1000 ; i ++ )
{
for ( int j = 2 ; j < i ; j ++ )
{
if ( i % j == 0 )
перейти во внешний мир ;
}
Консоль . WriteLine ( я );
внешний :;
}
}
В синтаксисе ассемблера CIL это выглядит так:
. метод Privateidebysig недействительный статический Main строка ( ] [ args ) cil управляемый
{
. входная точка
. Максстек 2
. locals init ( int32 V_0 ,
int32 V_1 )
ldc . i4 .2
стлок .0
бр . s IL_001f
IL_0004 : ldc . i4 .2
стлок .1
комн . s IL_0011
IL_0008 : ldloc .0
ldloc .1
rem
brfalse . s IL_001b
ldloc .1
ldc . i4 .1
добавить
stloc .1
IL_0011 : ldloc .1
ldloc .0
blt . s IL_0008
ldloc .0
call void [ mscorlib ] System . Консоль :: WriteLine ( int32 )
IL_001b : ldloc .0
ldc . i4.1
добавить
stloc.0
IL_001f : ldloc.0
ldc . i4 0x3e8
блт . с IL_0004
в отставку
}
Это всего лишь представление того, как CIL выглядит на уровне виртуальной машины (VM). При компиляции методы сохраняются в таблицах, а инструкции сохраняются в виде байтов внутри сборки, которая представляет собой переносимый исполняемый файл (PE).
Поколение [ править ]
Сборка CIL и инструкции генерируются либо компилятором, либо утилитой, называемой IL Assembler ( ILAsm ), которая поставляется со средой выполнения.
Собранный CIL также можно снова дизассемблировать в код с помощью дизассемблера IL (ILDASM). Существуют и другие инструменты, такие как .NET Reflector , которые могут декомпилировать CIL в язык высокого уровня (например, C# или Visual Basic ). Это делает CIL очень легкой целью для обратного проектирования. Эта черта является общей для байт-кода Java . Однако существуют инструменты, которые могут запутать код и сделать это так, что код не может быть легко читаемым, но при этом остается работоспособным.
Исполнение [ править ]
Сборка точно в срок [ править ]
Компиляция «точно в срок» (JIT) включает в себя преобразование байт-кода в код, который немедленно исполняется процессором. Преобразование выполняется постепенно во время выполнения программы. JIT-компиляция обеспечивает оптимизацию для конкретной среды, безопасность типов во время выполнения и проверку сборки. Для этого JIT-компилятор проверяет метаданные сборки на предмет несанкционированного доступа и соответствующим образом обрабатывает нарушения.
Предварительная компиляция [ править ]
Среды выполнения, совместимые с CLI, также имеют возможность выполнять предварительную компиляцию (AOT) сборки, чтобы ускорить ее выполнение за счет удаления процесса JIT во время выполнения.
В .NET Framework есть специальный инструмент под названием Native Image Generator (NGEN), который выполняет AOT. Другой подход к AOT — CoreRT , который позволяет компилировать код .Net Core в один исполняемый файл без зависимости от среды выполнения. В Mono также есть возможность выполнить AOT.
Инструкции указателя — C++/CLI [ править ]
Заметным отличием от байт-кода Java является то, что CIL поставляется с ldind
, stind
, ldloca
и множество инструкций вызова, которых достаточно для манипулирования указателями данных/функций, необходимых для компиляции кода C/C++ в CIL.
класс A {
общественный : виртуальный недействительный __stdcall meth () {}
};
void test_pointer_operations ( int param ) {
int k = 0 ;
int * ptr = & k ;
* ПТР = 1 ;
ПТР = & параметр ;
* ПТР = 2 ;
А а ;
А * птра = &а a ;
птра -> мет ();
}
Соответствующий код в CIL можно отобразить следующим образом:
. метод сборки static void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvCdecl )
test_pointer_operations ( int32 param ) cil Managed
{
. vtentry 1 : 1
// Размер кода 44 (0x2c)
. Максстек 2
. locals ([ 0 ] int32 * ptr ,
[ 1 ] valuetype A * V_1 ,
[ 2 ] valuetype A * a ,
[ 3 ] int32 k )
// k = 0;
IL_0000 : ЛДК . i4 .0
IL_0001 : stloc .3
// ptr = &k;
IL_0002 : ldloca . s k // инструкция загрузки локального адреса
IL_0004 : stloc .0
// *ptr = 1;
IL_0005 : ldloc.0 IL_0006
: ldc . i4 .1
IL_0007 : стоять . i4 // инструкция косвенного обращения
// ptr = ¶m
IL_0008 : ldarga . s param // инструкция загрузки адреса параметра
IL_000a : stloc .0
// *ptr = 2
IL_000b : ldloc .0
IL_000c : ldc . i4 .2
IL_000d : стоять . i4
// a = новый A;
IL_000e : ldloca . s a
IL_0010 : вызвать valuetype A * modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvThiscall ) ' A . { ctor } ' ( valuetype A * modopt ([ mscorlib ] System . Runtime . CompilerServices . IsConst ) modopt ([ mscorlib ] Система . Время выполнения . CompilerServices . IsConst ))
IL_0015 : pop
// ptra = &a;
IL_0016 : ldloca . IL_0018 ;
: // stloc .1
ptra->meth()
IL_0019 : ldloc.1 IL_001a
: dup
IL_001b : ldind . i4 // чтение VMT для виртуального вызова
IL_001c : ldind . i4
IL_001d : calli unmanaged stdcall void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvStdcall ) ( native int )
IL_0022 : ret
} // конец метода «Глобальные функции»::test_pointer_operations
См. также [ править ]
Ссылки [ править ]
- ^ «Промежуточный язык и исполнение» .
- ^ «Инфраструктура общего языка ECMA-335 (CLI)» .
- ^ «Что такое промежуточный язык (IL)/MSIL/CIL в .NET» . Проверено 17 февраля 2011 г.
CIL: ...Когда мы компилируем [a]. NET, он [преобразовывается] не напрямую в двоичный код, а в промежуточный язык. При запуске проекта каждый язык программирования .NET преобразуется в двоичный код CIL. Только некоторая часть CIL, необходимая во время выполнения, преобразуется в двоичный код. DLL и EXE .NET также находятся в форме CIL.
- ^ «HackTool:MSIL/SkypeCracker» . Майкрософт . Проверено 26 ноября 2019 г. .
- ^ Троелсен, Эндрю (2 мая 2009 г.). Преимущества CIL . ISBN 9781590598849 . Проверено 17 февраля 2011 г.
- ^ «Неуправляемые и управляемые расширения для C++, управляемых и .Net Framework» . www.visualcplusdotnet.com . Проверено 7 июля 2020 г.
Дальнейшее чтение [ править ]
- Бок, Джейсон (2002). CIL-программирование: под капотом .NET . Апресс. ISBN 978-1590590416 .