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

UptoLike

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-кода в виде графа потока управления.
4.1.1. Основные элементы графа потока управления
Граф потока управления – это ориентированный граф, узлы которого
соответствуют инструкциям CIL, а дуги изображают передачу управления
между инструкциями.
В качестве примера рассмотрим фрагмент программы на CIL:
.method private static void print(int32[] X) {
.locals init (int32 i)
Анализ кода на CIL
133
Глава 4. Анализ кода на CIL
4.1. Граф потока управления
Код метода в сборке .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]
132
CIL и системное программирование в Microsoft .NET
132                         CIL и системное программирование в Microsoft .NET   Анализ кода на CIL                                                  133


                                                                                             bne.un.s loop_body        [1]
Глава 4. Анализ кода на CIL                                                                  ldloc.0                   [2]
                                                                                             stloc.1                   [2]
                                                                                             leave.s exit              [3]
                                                                                             }
4.1. Граф потока управления                                                                  catch System.IndexOutOfRangeException {
                                                                                             pop                       [2]
     Код метода в сборке .NET представляет собой линейную последова-                         ldc.i4.m1                 [2]
тельность CIL-инструкций и массив описателей блоков обработки исклю-                         stloc.1                   [2]
чений. Так как представленный в теле метода алгоритм в общем случае                          leave.s exit              [3]
нелинейный, то есть содержит ветвления и циклы, то кодирование его в                         }
виде линейной последовательности требует определения семантики пере-                  exit: ldloc.1                    [2]
дачи управления от одной инструкции CIL к другой. Можно выделить че-                         ret                       [4]
тыре механизма передачи управления между инструкциями:                                }
        1. Явная передача управления с помощью инструкции перехода.                   Метод find выполняет поиск элемента k в массиве X. Если элемент
           При этом в параметре инструкции перехода указано относи-             найден, то возвращается его индекс. В противном случае возвращается -1.
           тельное смещение инструкции, на которую будет передано уп-           В листинге программы справа от каждой инструкции в квадратных скобках
           равление.                                                            приведен тип передачи управления от нее на следующую инструкцию.
        2. Неявная (или естественная) передача управления на следующую                Схема представления кода в виде линейной последовательности ин-
           инструкцию в последовательности.                                     струкций типична для ассемблерных языков и является наиболее ком-
        3. Передача управления на обработчик исключения при выходе (нор-        пактной. Действительно, бoльшая часть кода метода состоит из линейных
           мальном или аварийном) из защищенного блока. При такой пе-           последовательностей инструкций с неявной передачей управления, а так
           редаче управления просматривается массив описателей блоков           как неявная передача определяется порядком следования инструкций и
           обработки исключений до нахождения первого подходящего               не требует дополнительного кодирования, то код занимает меньше места.
           блока, из описателя этого блока берется адрес обработчика и                Некоторые метаинструменты, выполняющие только анализ CIL-ко-
           осуществляется переход на инструкцию по этому адресу.                да, могут непосредственно работать с линейной последовательностью ин-
        4. Передача управления между методами.                                  струкций. Это JIT-компиляторы, интерпретаторы, верификаторы и отлад-
     В качестве примера рассмотрим фрагмент программы на языке CIL:             чики. Но для метаинструментов, которые выполняют преобразование 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]                                     пользовать представление CIL-кода в виде графа потока управления.
     loop_body: ldloc.0                 [2]
                 ldc.i4.1               [2]                                     4.1.1. Основные элементы графа потока управления
                 add                    [2]                                          Граф потока управления – это ориентированный граф, узлы которого
                 stloc.0                [2]                                     соответствуют инструкциям CIL, а дуги изображают передачу управления
     loop_cond: ldarg.0                 [2]                                     между инструкциями.
                 ldloc.0                [2]                                          В качестве примера рассмотрим фрагмент программы на CIL:
                 ldelem.i4              [2]                                          .method private static void print(int32[] X) {
                 ldarg.1                [2]                                                 .locals init (int32 i)