Assembly Round Tripping and much more
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:
<span class="kwrd">using</span> Mono.Cecil;
<span class="kwrd">class</span> RoundTrip {
<span class="kwrd">static</span> <span class="kwrd">void</span> Main ()
{
<span class="kwrd">string</span> file = <span class="str">"hello.exe"</span>
<span class="kwrd">for</span> (<span class="kwrd">int</span> 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 :
<span class="kwrd">using</span> Mono.Cecil;
<span class="kwrd">using</span> Mono.Cecil.Cil;
<span class="kwrd">class</span> Pre_AOP_Era {
<span class="kwrd">static</span> <span class="kwrd">void</span> Main ()
{
<span class="kwrd">string</span> file = <span class="str">"hello.exe"</span>
IAssemblyDefinition asm = AssemblyFactory.GetAssembly (
file, LoadingType.Aggressive);
ITypeDefinition hello = asm.MainModule.Types [<span class="str">"Test.Hello"</span>];
IMethodDefinition main = hello.Methods [0]; <span class="rem">// get the Main method</span>
ICilWorker worker = main.Body.GetWorker ();
InsertBeforeRetInstruction (
worker, worker.Create (OpCodes.Ldstr, <span class="str">"And from Jb too!"</span>));
InsertBeforeRetInstruction (
worker, worker.Create (OpCodes.Call, <span class="kwrd">typeof</span> (Console).GetMethod (
<span class="str">"WriteLine"</span>, <span class="kwrd">new</span> Type [] {<span class="kwrd">typeof</span> (<span class="kwrd">string</span>)})));
AssemblyFactory.SaveAssembly (asm, file, AssemblyKind.Console);
}
<span class="kwrd">static</span> <span class="kwrd">void</span> 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:
Trackbacks
Use the following link to trackback from your own site:
http://www.evain.net/blog/articles/trackback/30