Московский государственный технический университет им. Н.Э. Баумана
Опубликован: 28.06.2006 | Доступ: свободный | Студентов: 12463 / 344 | Оценка: 4.54 / 3.83 | Длительность: 22:03:00
ISBN: 978-5-9556-0055-0
Лекция 8:

Анализ кода на CIL

Аннотация: Граф потока управления. Алгоритм преобразования линейной последовательности инструкций в граф потока управления.

Граф потока управления

Код метода в сборке .NET представляет собой линейную последовательность CIL-инструкций и массив описателей блоков обработки исключений. Так как представленный в теле метода алгоритм в общем случае нелинейный, то есть содержит ветвления и циклы, то кодирование его в виде линейной последовательности требует определения семантики передачи управления от одной инструкции CIL к другой. Можно выделить четыре механизма передачи управления между инструкциями:

  1. Явная передача управления с помощью инструкции перехода. При этом в параметре инструкции перехода указано относительное смещение инструкции, на которую будет передано управление.
  2. Неявная (или естественная) передача управления на следующую инструкцию в последовательности.
  3. Передача управления на обработчик исключения при выходе (нормальном или аварийном) из защищенного блока. При такой передаче управления просматривается массив описателей блоков обработки исключений до нахождения первого подходящего блока, из описателя этого блока берется адрес обработчика и осуществляется переход на инструкцию по этому адресу.
  4. Передача управления между методами.

В качестве примера рассмотрим фрагмент программы на языке CIL:

.method private static int32 find(int32[] X, int32 k) {
          .locals init (int32 i, int32 result)
          .try {
          ldc.i4.0        	[2]
          stloc.0          	[2]
          br.s    loop_cond 	[1]
loop_body: ldloc.0        	[2]
          ldc.i4.1        	[2]
          add          		[2]
          stloc.0        	[2]
loop_cond: ldarg.0        	[2]
          ldloc.0        	[2]
          ldelem.i4       	[2]
          ldarg.1        	[2]
      bne.un.s  loop_body 	[1]
      ldloc.0        		[2]
      stloc.1        		[2]
      leave.s  exit    		[3]
      }
      catch System.IndexOutOfRangeException {
      pop          		[2]
      ldc.i4.m1       		[2]
      stloc.1        		[2]
      leave.s  exit    		[3]
      }
exit: ldloc.1        		[2]
      ret          		[4]
}

Метод find выполняет поиск элемента k в массиве X. Если элемент найден, то возвращается его индекс. В противном случае возвращается -1. В листинге программы справа от каждой инструкции в квадратных скобках приведен тип передачи управления от нее на следующую инструкцию.

Схема представления кода в виде линейной последовательности инструкций типична для ассемблерных языков и является наиболее компактной. Действительно, бoльшая часть кода метода состоит из линейных последовательностей инструкций с неявной передачей управления, а так как неявная передача определяется порядком следования инструкций и не требует дополнительного кодирования, то код занимает меньше места.

Некоторые метаинструменты, выполняющие только анализ CIL-кода, могут непосредственно работать с линейной последовательностью инструкций. Это JIT-компиляторы, интерпретаторы, верификаторы и отладчики. Но для метаинструментов, которые выполняют преобразование CIL-кода, такое представление неудобно, так как при попытке вставить новую инструкцию в последовательность или удалить инструкцию из последовательности необходимо корректировать адреса во всех инструкциях перехода и во всех описателях блоков обработки исключений. Этих проблем можно избежать, если вместо линейной последовательности инструкций использовать представление CIL-кода в виде графа потока управления.

Анастасия Булинкова
Анастасия Булинкова
Рабочим названием платформы .NET было