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

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

Преобразование линейной последовательности инструкций в граф потока управления

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

Наш алгоритм будет работать на уровне метода, то есть в качестве входных данных для него будут выступать тело метода и массив предложений обработки исключений для этого метода. На выходе алгоритма будет построенный граф потока управления. Таким образом, для того чтобы построить набор графов потока управления для всей сборки, необходимо запустить этот алгоритм для каждого метода, входящего в сборку.

Итак, пусть дан массив инструкций P размера N и массив предложений обработки исключений EH размера M. Требуется построить граф потока управления и возвратить ссылку на блок тела метода построенного графа.

Мы будем предполагать, что в массивах P и EH адреса инструкций предварительно заменены на их номера (это касается встроенных операндов инструкций перехода, а также границ областей в предложениях обработки исключений). Кроме того, все массивы, которые мы будем рассматривать при описании алгоритма, включая массивы P и EH, будут индексироваться, начиная с нуля.

Напомним также, что каждое предложение в массиве EH имеет следующий набор полей:

  • Flags.

    Задает тип обработчика исключений: обработчик с фильтрацией по типу, обработчик с пользовательской фильтрацией, обработчик finally или обработчик fault.

  • TryOffset.

    Номер инструкции в массиве P, с которой начинается защищенная область.

  • TryLength.

    Количество инструкций, входящих в защищенную область.

  • HandlerOffset.

    Номер инструкции в массиве P, с которой начинается область обработчика.

  • HandlerLength.

    Количество инструкций, входящих в область обработчика.

  • ClassToken.

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

  • FilterOffset.

    Номер инструкции в массиве P, с которой начинается область фильтра (используется в случае обработчика с пользовательской фильтрацией).

Создание массива узлов

На первом этапе работы алгоритма мы создаем узел графа для каждой инструкции и формируем из созданных узлов массив.

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

Узлы записываются в массив Nodes, состоящий из N элементов. При этом в массиве Nodes сохраняется порядок инструкций, то есть если некоторая инструкция располагается в массиве P по индексу i, то соответствующий ей узел будет размещен в i-том элементе массива Nodes.

На C#-подобном псевдоязыке первый этап работы алгоритма можно записать следующим образом:

Nodes = новый массив узлов размера N;
for (int i = 0; i < N; i++)
{
  Nodes[i] = новый узел, содержащий информацию об инструкции P[i];
}

Следует особо отметить, что для инструкций безусловного перехода также создаются отдельные узлы. Инструкцию nop мы будем считать инструкцией безусловного перехода по относительному адресу 0. Эти узлы для инструкций безусловного перехода являются временными и на последнем этапе алгоритма удаляются из графа.

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