Assembly Round Tripping and much more

Posted by jbevain Sat, 13 Aug 2005 14:11:23 GMT


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 &lt; 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

Comments

Leave a response

Comments