Thanks to another few hacks today on Cecil, I can now do funny things. Assembly Round Tripping is one of them. It just mean that I can now load an Assembly with Cecil, and write it back. Without loss of data. Anyway Cecil for the moment does not deal with a lot of data :) Here is a sample code so that you can figure out by yourself:
using Mono.Cecil; class RoundTrip { static void Main () { string file = "hello.exe" for (int i = 0; i < 10; i++) AssemblyFactory.SaveAssembly (AssemblyFactory.GetAssembly ( file, LoadingType.Aggressive), file, AssemblyKind.Console); } }
Doing this ten times it plain useless. But now you are sure that the assembly is well round tripped.
Interesting huh ? But yeah, a bit useless as it is. If Cecil is able to read and assembly and write it back, it should also be possible to modify it. To go further, I have to assume that you've read the precedent post, that reveals the Hello World example. Now let's read this wonderful piece of code that will modify the Hello World :
using Mono.Cecil; using Mono.Cecil.Cil; class Pre_AOP_Era { static void Main () { string file = "hello.exe" IAssemblyDefinition asm = AssemblyFactory.GetAssembly ( file, LoadingType.Aggressive); ITypeDefinition hello = asm.MainModule.Types ["Test.Hello"]; IMethodDefinition main = hello.Methods [0]; // get the Main method ICilWorker worker = main.Body.GetWorker (); InsertBeforeRetInstruction ( worker, worker.Create (OpCodes.Ldstr, "And from Jb too!")); InsertBeforeRetInstruction ( worker, worker.Create (OpCodes.Call, typeof (Console).GetMethod ( "WriteLine", new Type [] {typeof (string)}))); AssemblyFactory.SaveAssembly (asm, file, AssemblyKind.Console); } static void InsertBeforeRetInstruction (ICilWorker worker, IInstruction ins) { IMethodBody body = worker.GetBody (); IInstruction ret = body.Instructions [body.Instructions.Count - 1]; worker.InsertBefore (ret, ins); } }
Basically, I retrieve here the type and a method defined in the precedent example, and using I add two instructions before the last instruction of this method. I just call Console.WriteLine with a new string "And from Jb too!" The ICilWorker interface defines methods to create and manipulate CIL streams. As it is not very complete, I've written here a little method to help in this task.
Unsurprisingly, by invoking the new executable, you'll be greeted twice:
newton:~/Sources/temp jbevain$ mono hello.exe Hello from Cecil! And from Jb too!
This feature of Cecil is a terribly exciting one. It leds to many applications, including the re-write of the core of AspectDNG, the Aspect Weaver Thomas Gil and I are working on.
Don't be desapointed, but once again, this is still not in SVN, but it shows the lasts progress of Cecil. I hope you enjoy it as much as I do :)
Oh, and because he loves pictures, here is one of Sebastien Ros, one of my mentor, and me: