Общий промежуточный язык

Промежуточное представление, определенное в спецификации CLI

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 Defender продолжают ссылаться на двоичные файлы, скомпилированные с его помощью, как на MSIL. [4]

Общая информация

Во время компиляции языков программирования CLI исходный код транслируется в код CIL, а не в объектный код, специфичный для платформы или процессора . CIL — это набор инструкций, не зависящий от процессора и платформы, который может выполняться в любой среде, поддерживающей Common Language Infrastructure, например, среда выполнения .NET в Windows или кроссплатформенная среда выполнения Mono . Теоретически это устраняет необходимость распространять различные исполняемые файлы для различных платформ и типов процессоров. Код CIL проверяется на безопасность во время выполнения, обеспечивая лучшую безопасность и надежность, чем изначально скомпилированные исполняемые файлы. [5] [6]

Процесс выполнения выглядит следующим образом:

  1. Исходный код преобразуется в байт-код CIL и создается сборка CLI .
  2. При выполнении сборки CIL ее код передается через JIT-компилятор среды выполнения для генерации собственного кода. Также может использоваться предварительная компиляция, которая исключает этот шаг, но за счет переносимости исполняемого файла.
  3. Процессор компьютера выполняет машинный код.

Инструкции

Байт-код CIL содержит инструкции для следующих групп задач:

Вычислительная модель

Общий промежуточный язык является объектно-ориентированным и основан на стеке , что означает, что параметры инструкций и результаты хранятся в одном стеке, а не в нескольких регистрах или других областях памяти, как в большинстве языков программирования .

Код, который складывает два числа на языке ассемблера x86 , где eax и edx указывают два разных регистра общего назначения :

добавить eax , edx  

Код на промежуточном языке (IL), где 0 — это eax, а 1 — это edx:

ldloc . 0 // поместить локальную переменную 0 в стек ldloc . 1 // поместить локальную переменную 1 в стек add // извлечь и добавить два верхних элемента стека, затем поместить результат в стек stloc . 0 // извлечь и сохранить верхний элемент стека в локальной переменной 0    

В последнем примере значения двух регистров, eax и edx, сначала помещаются в стек. Когда вызывается инструкция добавления, операнды "выталкиваются" или извлекаются, а результат "выталкивается" или сохраняется в стеке. Затем полученное значение выталкивается из стека и сохраняется в eax.

Объектно-ориентированные концепции

CIL разработан как объектно-ориентированный. Можно создавать объекты, вызывать методы и использовать другие типы членов, такие как поля.

Каждый метод должен (за некоторыми исключениями) находиться в классе. То же самое касается и этого статического метода:

. class public Foo { . method public static int32 Add ( int32 , int32 ) cil managed { . maxstack 2 ldarg . 0 // загрузить первый аргумент; ldarg . 1 // загрузить второй аргумент; add // добавить их; ret // вернуть результат; } }                       

Метод Add не требует объявления какого-либо экземпляра Foo, поскольку он объявлен как статический, и его можно использовать в C# следующим образом:

int r = Foo.Add ( 2,3 ) ; // 5     

На языке CIL это будет выглядеть так:

ldc.i4.2 ldc.i4.3 call int32 Foo :: Add ( int32 , int32 ) stloc.0   

Классы экземпляров

Класс экземпляра содержит по крайней мере один конструктор и несколько членов экземпляра . Следующий класс имеет набор методов, представляющих действия объекта Car.

. class public Car { . method public specialname rtspecialname instance void . ctor ( int32 , int32 ) cil managed { /* Конструктор */ }                 . method public void Move ( int32 ) cil manage { /* Пропуск реализации */ } . method public void TurnRight () cil manage { /* Пропуск реализации */ } . method public void TurnLeft () cil manage { /* Пропуск реализации */ } . method public void Brake () cil manage { /* Пропуск реализации */ } }                                   

Создание объектов

В C# экземпляры классов создаются следующим образом:

Автомобиль myCar = новый автомобиль ( 1 , 4 ); Автомобиль yourCar = новый автомобиль ( 1 , 3 );           

И эти утверждения примерно совпадают с этими инструкциями в CIL:

ldc.i4.1 ldc.i4.4 newobj instance void Car :: . ctor ( int , int ) stloc.0 // myCar = new Car ( 1 , 4 ) ; ldc.i4.1 ldc.i4.3 newobj instance void Car :: . ctor ( int , int ) stloc.1 // yourCar = new Car ( 1 , 3 ) ;          

Вызов методов экземпляра

Методы экземпляра вызываются в C# следующим образом:

myCar . Переместить ( 3 );

Как указано в CIL:

ldloc . 0 // Загрузить объект "myCar" в стек ldc . i4 . 3 вызвать экземпляр void Car :: Move ( int32 )    

Метаданные

Common Language Infrastructure (CLI) записывает информацию о скомпилированных классах в виде метаданных . Подобно библиотеке типов в Component Object Model , это позволяет приложениям поддерживать и обнаруживать интерфейсы, классы, типы, методы и поля в сборке. Процесс чтения таких метаданных называется « рефлексией ».

Метаданные могут быть данными в форме «атрибутов». Атрибуты можно настраивать, расширяя Attributeкласс. Это мощная функция. Она позволяет создателю класса украсить его дополнительной информацией, которую потребители класса могут использовать различными осмысленными способами в зависимости от области применения.

Пример

Ниже приведена базовая программа "Hello, World!", написанная на ассемблере CIL. Она выведет на экран строку "Hello, world!".

. assembly Hello {} . assembly extern mscorlib {} . method static void Main () { . entrypoint . maxstack 1 ldstr "Привет, мир!" call void [ mscorlib ] System . Console :: WriteLine ( string ) 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 ) goto external ; } Console.WriteLine ( i ) ; external :; } }                                   

В синтаксисе ассемблера CIL это выглядит так:

. метод private hidebysig static void Main ( string [] args ) cil управляемый { . entrypoint . maxstack 2 . locals init ( int32 V_0 , int32 V_1 )                  ООО . 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). При компиляции методы хранятся в таблицах, а инструкции хранятся в виде байтов внутри сборки, которая является Portable Executable (PE).

Поколение

Сборка CIL и инструкции генерируются либо компилятором, либо утилитой, называемой ассемблером IL ( ILAsm ), которая поставляется вместе со средой выполнения.

Собранный CIL также можно снова разобрать в код с помощью IL Disassembler (ILDASM). Существуют и другие инструменты, такие как .NET Reflector , которые могут декомпилировать CIL в высокоуровневый язык (например, C# или Visual Basic ). Это делает CIL очень легкой целью для обратного проектирования. Эта черта свойственна и байт-коду Java . Однако существуют инструменты, которые могут запутать код и сделать так, что код будет нелегко читать, но все равно будет запускаться.

Исполнение

Компиляция точно в срок

Компиляция Just-in-time (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 { public : virtual void __stdcall meth () {} }; void test_pointer_operations ( int param ) { int k = 0 ; int * ptr = & k ; * ptr = 1 ; ptr = & param ; * ptr = 2 ; A a ; A * ptra = &a a ; птра -> мет (); }                             

Соответствующий код на языке CIL можно представить следующим образом:

. метод сборки static void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvCdecl ) test_pointer_operations ( int32 param ) cil managed { . vtentry 1 : 1 // Размер кода 44 (0x2c) . maxstack 2 . locals ([ 0 ] int32 * ptr , [ 1 ] valuetype A * V_1 , [ 2 ] valuetype A * a , [ 3 ] int32 k ) // k = 0; IL_0000 : ldc . 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 ]                                                                        Система . Время выполнения . Службы компилятора . IsConst ) modopt ([ mscorlib ] System . Runtime . 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 } // конец метода 'Global Functions'::test_pointer_operations                           

Смотрите также

Ссылки

  1. ^ «Промежуточный язык и исполнение». 19 апреля 2023 г.
  2. ^ «ECMA-335 Инфраструктура общего языка (CLI)».
  3. ^ "Что такое Intermediate Language(IL)/MSIL/CIL в .NET" . Получено 2011-02-17 . CIL: ... Когда мы компилируем [проект]. NET, он [преобразуется] не напрямую в двоичный код, а в промежуточный язык. Когда проект запускается, каждый язык программирования .NET преобразуется в двоичный код в CIL. Только некоторая часть CIL, которая требуется во время выполнения, преобразуется в двоичный код. DLL и EXE .NET также находятся в форме CIL.
  4. ^ "HackTool:MSIL/SkypeCracker". Microsoft . Получено 26 ноября 2019 г. .
  5. ^ Троелсен, Эндрю (2009-05-02). Преимущества CIL. Apress. ISBN 9781590598849. Получено 2011-02-17 .
  6. ^ «Неуправляемые, управляемые расширения для C++, управляемые и .Net Framework». www.visualcplusdotnet.com . Получено 2020-07-07 .

Дальнейшее чтение

  • Бок, Джейсон (2002). Программирование CIL: Под капотом .NET . Apress. ISBN 978-1590590416.
  • Инфраструктура общего языка (стандарт ECMA-335)
  • «ECMA C# и стандарты общей языковой инфраструктуры» на веб-сайте Visual Studio
  • Программа Hello world на языке CIL
  • Скорость: NGen повышает производительность с помощью новых мощных функций -- MSDN Magazine, апрель 2005 г.
Взято с "https://en.wikipedia.org/w/index.php?title=Общий_промежуточный_язык&oldid=1262663531"