Инъекции CLR: замена методов во время выполнения
ОГЛАВЛЕНИЕ
Страница 1 из 4
Многие из нас, наверняка, были заинтересованы в том, как работает универсальный язык CLR. Одной из наиболее интересных вещей является динамический компилятор JIT (Just In Time Compiler). Мы рассмотрим то, как JIT компилирует MSIL и создадим утилиту, которая позволяет программным образом заменить любой метод (JIT) другим во время выполнения. Мы также создадим отладочную утилиту, которая прехватывает JIT-вызовы и выводит в консоль информацию о диагноcnbrt. Компилятор JIT
Microsoft Intermediate Language или MSIL (более известен как Common Intermediate Language (CIL)) является языком низшего уровня, типа ассемблера. Все языки .NET компилируются в MSIL (с некоторыми исключениями C++/CLI). Процессоры не могут выполнять MSIL напрямую (может, для .NET в будущем появится технология типа ARM Jazelle). Компилятор JIT используется для преобразования MSIL в машинный код. Метод будет скомпилирован единожды компилятором JIT, а CLR сохранит (кэширует) машинный код, который произведет JIT, для последующих вызовов.Процесс компиляции должен быть очень быстрым, поскольку он происходит во время выполнения. Поскольку MSIL является языком низшего уровня, его система кодов операций с легкостью преобразуется в машинную специфическую систему кодов операций. Сам процесс компиляции использует кое-что под названием JITStub. JITStub - это блок вспомогательного машинного кода, которым обладает каждый метод. JITstub в исходной версии содержит код, который вызывает JIT для метода. После того, как метод будет скомпилирован при помощи JIT, JITstub будет заменен кодом, который вызывает машинный код, созданный JIT .
000EFA60 E86488D979 call 79E882C9 // До JIT. Вызов метода JITКаждый класс имеет таблицу методов. Таблица методов имеет адреса всех JITStub для методов класса. Таблица метода используется во время компиляции JIT для разрешения вспомогательного кода JIT. Метод, который уже был откомпилирован JIT, не будет включен в эту таблицу, машинный код, созданный JIT, вызовет адрес вспомогательного кода напрямую. Далее мы привели выходную информацию таблицы методов из SOS. Колонка entry содержит адреса кодов.
000EFA60 E97BC1CB00 jmp 00DABBE0 // После JIT. Переход к ассемблерному коду, созданному JIT
MethodDesc TableТакже есть возможность вызвать компилятор JIT из управляемого кода без вызова самого метода. Метод System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod заставит JIT скомпилировать метод.
Entry MethodDesc JIT Name
79371278 7914b928 PreJIT System.Object.ToString()
7936b3b0 7914b930 PreJIT System.Object.Equals(System.Object)
7936b3d0 7914b948 PreJIT System.Object.GetHashCode()
793624d0 7914b950 PreJIT System.Object.Finalize()
000efa60 00d77ce0 JIT ReplaceExample.StaticClassB.A()
000efa70 00d77ce8 NONE ReplaceExample.StaticClassB.B()