Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 77 стр.

UptoLike

Напомним также, что каждое предложение в массиве EH имеет следу-
ющий набор полей:
Flags.
Задает тип обработчика исключений: обработчик с фильтрацией
по типу, обработчик с пользовательской фильтрацией, обработ-
чик finally или обработчик fault.
TryOffset.
Номер инструкции в массиве P, с которой начинается защищен-
ная область.
TryLength.
Количество инструкций, входящих в защищенную область.
HandlerOffset.
Номер инструкции в массиве P, с которой начинается область
обработчика.
HandlerLength.
Количество инструкций, входящих в область обработчика.
ClassToken.
Токен метаданных, обозначающий тип исключения (использу-
ется в случае обработчика с фильтрацией по типу).
FilterOffset.
Номер инструкции в массиве P, с которой начинается область
фильтра (используется в случае обработчика с пользовательской
фильтрацией).
4.2.1. Создание массива узлов
На первом этапе работы алгоритма мы создаем узел графа для каждой
инструкции и формируем из созданных узлов массив.
На входе первого этапа мы имеем массив P. Для каждой инструкции,
входящей в массив P, мы создаем соответствующий ей узел графа. В этот
узел записываются все данные об инструкции, кроме информации о пере-
даче управления и принадлежности блокам. Другими словами, созданные
узлы не связываются друг с другом дугами и не имеют ссылки на родитель-
ский блок.
Узлы записываются в массив Nodes, состоящий из N элементов. При
этом в массиве Nodes сохраняется порядок инструкций, то есть если неко-
торая инструкция располагается в массиве P по индексу i, то соответству-
ющий ей узел будет размещен в i-том элементе массива Nodes.
На C#-подобном псевдоязыке первый этап работы алгоритма можно
записать следующим образом:
Nodes = новый массив узлов размера N;
for (int i = 0; i < N; i++)
{
Анализ кода на CIL
141
Однако путем введения в граф дополнительных дуг, задающих иерар-
хию блоков, мы можем сделать операцию поиска блока, в который непо-
средственно входит некоторая инструкция, очень эффективной.
Пусть каждый узел графа, кроме блока тела метода, будет соединен
особой дугой с блоком, в который этот узел непосредственно входит. В ре-
зультате добавления таких дуг в структуре графа получается дерево блоков.
На рис. 4.4 изображена схема такого дерева, на которой наши дополни-
тельные дуги обозначены незакрашенными стрелками, а дуги, соединяю-
щие защищенные блоки с блоками обработки исключений, обозначены
пунктирными стрелками. Обычные дуги графа потока управления, задаю-
щие передачу управления между инструкциями, на схеме не изображены.
Понятно, что операция поиска блока, в который входит инструкция,
на графе, включающем дерево блоков, сводится к переходу по одной дуге
от инструкции к блоку. Эта операция выполняется за константное время,
то есть не зависит ни от количества защищенных блоков, ни от количест-
ва инструкций в блоке.
4.2. Преобразование линейной
последовательности инструкций
в граф потока управления
Разработчик любого метаинструмента, использующего граф потока
управления в процессе анализа CIL-кода, сталкивается с проблемой преоб-
разования линейной последовательности инструкций в граф потока упра-
вления. В данной главе мы рассмотрим алгоритм такого преобразования.
Наш алгоритм будет работать на уровне метода, то есть в качестве
входных данных для него будут выступать тело метода и массив предложе-
ний обработки исключений для этого метода. На выходе алгоритма будет
построенный граф потока управления. Таким образом, для того чтобы по-
строить набор графов потока управления для всей сборки, необходимо за-
пустить этот алгоритм для каждого метода, входящего в сборку.
Итак, пусть дан массив инструкций P размера N и массив предложе-
ний обработки исключений EH размера M. Требуется построить граф пото-
ка управления и возвратить ссылку на блок тела метода построенного
графа.
Мы будем предполагать, что в массивах P и EH адреса инструкций
предварительно заменены на их номера (это касается встроенных операн-
дов инструкций перехода, а также границ областей в предложениях обра-
ботки исключений). Кроме того, все массивы, которые мы будем рассма-
тривать при описании алгоритма, включая массивы P и EH, будут индекси-
роваться, начиная с нуля.
140
CIL и системное программирование в Microsoft .NET
140                         CIL и системное программирование в Microsoft .NET   Анализ кода на CIL                                                   141


     Однако путем введения в граф дополнительных дуг, задающих иерар-              Напомним также, что каждое предложение в массиве EH имеет следу-
хию блоков, мы можем сделать операцию поиска блока, в который непо-             ющий набор полей:
средственно входит некоторая инструкция, очень эффективной.                           • Flags.
     Пусть каждый узел графа, кроме блока тела метода, будет соединен                   Задает тип обработчика исключений: обработчик с фильтрацией
особой дугой с блоком, в который этот узел непосредственно входит. В ре-                по типу, обработчик с пользовательской фильтрацией, обработ-
зультате добавления таких дуг в структуре графа получается дерево блоков.               чик finally или обработчик fault.
На рис. 4.4 изображена схема такого дерева, на которой наши дополни-                  • TryOffset.
тельные дуги обозначены незакрашенными стрелками, а дуги, соединяю-                     Номер инструкции в массиве P, с которой начинается защищен-
щие защищенные блоки с блоками обработки исключений, обозначены                         ная область.
пунктирными стрелками. Обычные дуги графа потока управления, задаю-                   • TryLength.
щие передачу управления между инструкциями, на схеме не изображены.                     Количество инструкций, входящих в защищенную область.
     Понятно, что операция поиска блока, в который входит инструкция,                 • HandlerOffset.
на графе, включающем дерево блоков, сводится к переходу по одной дуге                   Номер инструкции в массиве P, с которой начинается область
от инструкции к блоку. Эта операция выполняется за константное время,                   обработчика.
то есть не зависит ни от количества защищенных блоков, ни от количест-                • HandlerLength.
ва инструкций в блоке.                                                                  Количество инструкций, входящих в область обработчика.
                                                                                      • ClassToken.
4.2. Преобразование линейной                                                            Токен метаданных, обозначающий тип исключения (использу-
                                                                                        ется в случае обработчика с фильтрацией по типу).
последовательности инструкций                                                         • FilterOffset.
в граф потока управления                                                                Номер инструкции в массиве P, с которой начинается область
                                                                                        фильтра (используется в случае обработчика с пользовательской
     Разработчик любого метаинструмента, использующего граф потока                      фильтрацией).
управления в процессе анализа CIL-кода, сталкивается с проблемой преоб-
разования линейной последовательности инструкций в граф потока упра-            4.2.1. Создание массива узлов
вления. В данной главе мы рассмотрим алгоритм такого преобразования.                 На первом этапе работы алгоритма мы создаем узел графа для каждой
     Наш алгоритм будет работать на уровне метода, то есть в качестве           инструкции и формируем из созданных узлов массив.
входных данных для него будут выступать тело метода и массив предложе-               На входе первого этапа мы имеем массив P. Для каждой инструкции,
ний обработки исключений для этого метода. На выходе алгоритма будет            входящей в массив P, мы создаем соответствующий ей узел графа. В этот
построенный граф потока управления. Таким образом, для того чтобы по-           узел записываются все данные об инструкции, кроме информации о пере-
строить набор графов потока управления для всей сборки, необходимо за-          даче управления и принадлежности блокам. Другими словами, созданные
пустить этот алгоритм для каждого метода, входящего в сборку.                   узлы не связываются друг с другом дугами и не имеют ссылки на родитель-
     Итак, пусть дан массив инструкций P размера N и массив предложе-           ский блок.
ний обработки исключений EH размера M. Требуется построить граф пото-                Узлы записываются в массив Nodes, состоящий из N элементов. При
ка управления и возвратить ссылку на блок тела метода построенного              этом в массиве Nodes сохраняется порядок инструкций, то есть если неко-
графа.                                                                          торая инструкция располагается в массиве P по индексу i, то соответству-
     Мы будем предполагать, что в массивах P и EH адреса инструкций             ющий ей узел будет размещен в i-том элементе массива Nodes.
предварительно заменены на их номера (это касается встроенных операн-                На C#-подобном псевдоязыке первый этап работы алгоритма можно
дов инструкций перехода, а также границ областей в предложениях обра-           записать следующим образом:
ботки исключений). Кроме того, все массивы, которые мы будем рассма-                 Nodes = новый массив узлов размера N;
тривать при описании алгоритма, включая массивы P и EH, будут индекси-               for (int i = 0; i < N; i++)
роваться, начиная с нуля.                                                            {