Программно разобрать CIL

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

Итак, как вы программно разбираете CIL на .NET?

Обратите внимание, что я не хочу, чтобы результат был в форме для человека. Я хочу написать метапрограммы, чтобы манипулировать CIL, сгенерированным из других программ.

Ответ 1

Вы можете получить достаточно далеко, просто используя массив байтов из метода GetILAsByteArray, но вам нужно будет написать парсинг самих байтов (если вы не хотите полагаться на стороннюю библиотеку).

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

Чтобы получить коды, вы можете посмотреть структуру OpCodes (MSDN) из System.Reflection.Emit. Если вы перечислите все поля, вы можете легко создать таблицу поиска для чтения байтов:

// Iterate over all byte codes to build lookup table
for fld in typeof<OpCodes>.GetFields() do
  let code = fld.GetValue(null) :?> OpCode
  printfn "%A (%d + %A)" code.Name code.Size code.OperandType

Свойство code.Value дает вам значение eithre byte или int16 кода. Свойство code.Size указывает вам, является ли это 1 или 2 байтовым кодом, а свойство OperandType указывает, какие аргументы следуют за кодом (количество байтов и значение объясняется в MSDN). Я не помню, как именно вам нужно обрабатывать такие вещи, как маркеры, относящиеся к i.e. MethodInfo, но я думаю, вы сможете это понять!

Ответ 2

Библиотека Mono Cecil - http://www.mono-project.com/Cecil должна делать то, что вам нужно, я знаю, что она используется, по крайней мере, в одном профиле .Net.

Ответ 3

Одной из интересных альтернатив использованию Cecil было бы воскресить проект AbsIL. Сесил хорошо написан и хорошо используется, но, вероятно, вы не можете подойти к проблеме, если вы пишете ее в F #. Абсолютный проект был запущен одновременно с F #, чтобы позволить OCaml и F # читать и писать IL, поскольку он был взят как проект F # и теперь является только задней частью компилятора F #. Однако код для чтения и записи IL по-прежнему существует и теоретически может быть отделен от компилятора F # и внесен в полезную библиотеку в его собственном праве. Разделение кода AbsIL от остальной части компилятора F # не является полностью тривиальным, но должно быть возможным, если у вас есть свободное время и определенное количество определений. Если вы чувствуете себя очень храбрым, вы также можете посмотреть, как скрестить его с OCaml.

Ответ 4

Я сделал несколько манипуляций с помощью проекта Mono Cecil. Это довольно простой API.