How to get the correct method reference when executing a JMP statement for a method that is in another assembly

I have the following code which basically creates DynamicAssembly with 2 types with one public method.

        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly
                (new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule("Main");
        var type1 = module.DefineType("type1");


        var method1 = type1.DefineMethod
                      (
                        "Method1", MethodAttributes.Public, typeof(void), null
                      );

        var gen = method1.GetILGenerator();
        gen.Emit(OpCodes.Ret);

        var t1 = type1.CreateType();

        var createdMethod1 = t1.GetMethod("Method1");

        var type2 = module.DefineType("type2");

        var method2 = type2.DefineMethod
                      (
                        "Method2", MethodAttributes.Public, typeof(void), null
                      );


        byte[] ilCodes = new byte[5];
        ilCodes[0] = (byte)OpCodes.Jmp.Value;
        ilCodes[1] = (byte)(createdMethod1.MetadataToken & 0xFF);
        ilCodes[2] = (byte)(createdMethod1.MetadataToken >> 8 & 0xFF);
        ilCodes[3] = (byte)(createdMethod1.MetadataToken >> 16 & 0xFF);
        ilCodes[4] = (byte)(createdMethod1.MetadataToken >> 24 & 0xFF);

        method2.SetMethodBody(ilCodes, ilCodes.Length, null, null, null);


        var obj = Activator.CreateInstance(type2.CreateType());

        obj.GetType().GetMethod("Method2").Invoke(obj, null);

      

Whenever I make a call to type2.method2 (), I have a JMP instruction for type1.method1 ().

It works like a charm, both types are in the same assembly.

Now if I want to redirect to a type that is in another assembly, how can I get the correct assembly / module reference for the JMP command to succeed. If I just do this:

        byte[] ilCodes = new byte[5];
        ilCodes[0] = (byte)OpCodes.Jmp.Value;
        ilCodes[1] = (byte)(methodFromOtherAssembly.MetadataToken & 0xFF);
        ilCodes[2] = (byte)(methodFromOtherAssembly.MetadataToken >> 8 & 0xFF);
        ilCodes[3] = (byte)(methodFromOtherAssembly.MetadataToken >> 16 & 0xFF);
        ilCodes[4] = (byte)(methodFromOtherAssembly.MetadataToken >> 24 & 0xFF);

      

It keeps failing with the IndexNotFound exception.

I want to do this using Raw IL byte instructions.

+3


source to share


1 answer


Metadata tokens are not globally unique. They are resolved in the context of the calling method module. You need to use GetMetadataToken in the module to get the corresponding token. Your first example works because the methods are using the same module.

This will give the correct token from the dynamic module:



byte[] ilCodes = new byte[5];
int token = module.GetMetadataToken(methodFromOtherAssembly).Token;
ilCodes[0] = (byte)OpCodes.Jmp.Value;
ilCodes[1] = (byte)(token & 0xFF);
ilCodes[2] = (byte)(token >> 8 & 0xFF);
ilCodes[3] = (byte)(token >> 16 & 0xFF);
ilCodes[4] = (byte)(token >> 24 & 0xFF);

      

+6


source







All Articles