Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

Общий промежуточный язык ( CIL ), ранее называвшийся Microsoft Intermediate Language ( MSIL ) или Intermediate Language ( IL ), [1] - это набор двоичных инструкций промежуточного языка, определенный в спецификации Common Language Infrastructure (CLI). [2] Инструкции CIL выполняются CLI-совместимой средой выполнения, такой как Common Language Runtime . Языки, предназначенные для компиляции CLI в CIL. КСС является объектно-ориентированным , стековый байт - код . Время выполнения обычно точно в сроккомпилировать инструкции CIL в машинный код .

CIL был первоначально известен как Microsoft Intermediate Language (MSIL) во время бета-версий языков .NET. Благодаря стандартизации C # и CLI байт-код теперь официально известен как CIL. [3] В описаниях вирусов Защитника Windows двоичные файлы, скомпилированные с его помощью, по-прежнему называются MSIL. [4]

Общая информация [ править ]

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

Процесс выполнения выглядит так:

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

Инструкции [ править ]

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

  • Загрузить и сохранить
  • Арифметика
  • Преобразование типов
  • Создание и манипулирование объектами
  • Управление стеком операндов (push / pop)
  • Передача управления (разветвление)
  • Вызов и возврат метода
  • Выбрасывание исключений
  • Мониторинг параллелизма
  • Манипуляции с указателями данных и функций, необходимые для C ++ / CLI и небезопасного кода C #

Вычислительная модель [ править ]

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

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

добавить  eax ,  edx

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

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

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

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

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

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

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

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

int  r  =  Foo . Добавить ( 2 ,  3 );  // 5

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

ldc . i4 . 2 ЖК . i4 . 3 вызовите  int32  Foo :: Add ( int32 ,  int32 ) stloc . 0

Классы экземпляров [ править ]

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

. class  public  Car  {  . Метод  общественного  specialname  rtspecialname  инстанции  недействительным  . ctor ( int32 ,  int32 )  cil  managed  {  / * Конструктор * /  } . method  public  void  Move ( int32 )  cil  managed  {  / * Опускается реализация * /  }  . method  public  void  TurnRight ()  cil  managed  {  / * Без реализации * /  }  . method  public  void  TurnLeft ()  cil  managed  {  / * Без реализации * /  }  . method  public  void  Brake ()  cil  managed  {  / * Пропуск реализации * / } }

Создание объектов [ править ]

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

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

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

ldc . i4 . 1 ЖК . i4 . 4 экземпляра newobj  void Car ::. т е р ( INT , INT ) stloc . 0 // myCar = new Car (1, 4); ldc . i4 . 1 ЖК . i4 . 3 экземпляра newobj void Car ::. т е р ( 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) записывает информацию о скомпилированных классов как метаданные . Подобно библиотеке типов в объектной модели компонентов , это позволяет приложениям поддерживать и обнаруживать интерфейсы, классы, типы, методы и поля в сборке. Процесс чтения таких метаданных называется « отражением ».

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

Пример [ править ]

Ниже представлена ​​базовая программа Hello, World, написанная на CIL. Будет отображена строка «Hello, world!».

. сборка  Привет  {} . сборка  extern  mscorlib  {} . метод  static  void  Main () {  . точка входа  . maxstack  1  ldstr  "Привет, мир!"  называют  недействительным  [ mscorlib ] System . Console :: 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 )  goto  outer ;  }  Консоль . WriteLine ( i );  внешний:;  } }

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

. метод  private  hidebysig  static  void  Main ( string []  args )  cil  managed {  . точка входа  . maxstack  2  . местные  инициализации  ( int32  v_0 ,  int32  v_1 ) ldc . i4 .2  stloc .0  br . s  IL_001f  IL_0004 :  ldc . i4 0,2  stloc 0,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  blt . s  IL_0004  ret }

Это просто представление того, как CIL выглядит на уровне виртуальной машины (ВМ). При компиляции методы сохраняются в таблицах, а инструкции хранятся в байтах внутри сборки, которая является переносимым исполняемым файлом (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.

class  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  *  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 :  stind . i4  // косвенная инструкция // ptr = & param  IL_0008 :  ldarga . s  param  // команда загрузки адреса параметра  IL_000a :  stloc .0 // * ptr = 2  IL_000b :  ldloc .0  IL_000c :  ldc . i4 .2  IL_000d :  stind . i4 // a = new A;  IL_000e :  ldloca . S  IL_0010 : вызов ValueType *     modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvThiscall )  ' A. { ctor } ' ( valuetype  A *  modopt ([ mscorlib ] System . Runtime . CompilerServices . IsConst )  modopt ([ mscorlib ] System . Runtime . CompilerServices . IsConst ) )  IL_0015 :  поп// ptra = & a;  IL_0016 :  ldloca . s  a  IL_0018 :  stloc .1 // ptra-> meth ();  IL_0019 :  ldloc .1  IL_001a :  dup  IL_001b :  ldind . i4  // чтение VMT для виртуального вызова  IL_001c :  ldind . i4  IL_001d :  каллусы  неуправляемого  STDCALL  недействительный  modopt ([ mscorlib ] System . Время воспроизведение . CompilerServices .CallConvStdcall ) ( native  int )  IL_0022 :  ret }  // конец метода 'Global Functions' :: test_pointer_operations

См. Также [ править ]

  • Список инструкций CIL
  • Список языков интерфейса командной строки

Ссылки [ править ]

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

Дальнейшее чтение [ править ]

  • Бок, Джейсон (2002). Программирование на CIL: под капотом .NET . Апресс. ISBN 978-1590590416.

Внешние ссылки [ править ]

  • Инфраструктура общего языка (стандарт ECMA-335)
  • «Стандарты ECMA C # и общеязыковой инфраструктуры» на веб-сайте Visual Studio.
  • Программа Hello World в CIL
  • Скорость: NGen повышает вашу производительность с помощью новых мощных функций - MSDN Magazine, апрель 2005 г.