Программно разобрать 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.