Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If/else and while branches in Mono.Cecil

AFAIK, Cecil does not support DefineLabel and MarkLabel. What are the alternatives to use (e.g. generating Nop opcodes) to replace labels when working with if-else and while branches?

For example:

public void Run(bool someParam)
{
    int someInt = 0;
    while (someParam)
    {
        someInt = someInt + 1;
        if (someInt == 10) someParam = false;
        System.Console.WriteLine(someInt);
    }
}

would have the following decompiled Reflection.Emit codes:

Label whileLabel = gen.DefineLabel();
Label label1 = gen.DefineLabel();
Label label2 = gen.DefineLabel();
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Br_S,label1);
gen.MarkLabel(whileLabel);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Add);
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Ldc_I4_S,10);
gen.Emit(OpCodes.Ceq);
gen.Emit(OpCodes.Stloc_1);
gen.Emit(OpCodes.Ldloc_1);
gen.Emit(OpCodes.Brfalse_S,label2);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Starg_S,1);
gen.MarkLabel(label2);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Call,writeLineMethod);
gen.MarkLabel(label1);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Stloc_2);
gen.Emit(OpCodes.Ldloc_2);
gen.Emit(OpCodes.Brtrue_S,whileLabel);
gen.Emit(OpCodes.Ret);

What could I do to "mark" labels in Cecil?

like image 386
MiP Avatar asked Dec 06 '25 18:12

MiP


1 Answers

Basically you pass the target instruction when creating the jump, something like:

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System; 
using System.Linq;
using BindingFlags = System.Reflection.BindingFlags;

using Cecilifier.Runtime;

public class SnippetRunner
{
    public static void Main(string[] args)
    {
        var assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("name", Version.Parse("1.0.0.0")), "moduleName", ModuleKind.Dll);
        var t1 = new TypeDefinition("", "Foo", TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.NotPublic, assembly.MainModule.TypeSystem.Object);
        assembly.MainModule.Types.Add(t1);
        t1.BaseType = assembly.MainModule.TypeSystem.Object;
        var Foo_ctor_ = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, assembly.MainModule.TypeSystem.Void);
        t1.Methods.Add(Foo_ctor_);
        var il1 = Foo_ctor_.Body.GetILProcessor();
        var Ldarg_02 = il1.Create(OpCodes.Ldarg_0);
        il1.Append(Ldarg_02);
        var Call3 = il1.Create(OpCodes.Call, assembly.MainModule.ImportReference(TypeHelpers.DefaultCtorFor(t1.BaseType)));
        il1.Append(Call3);
        var Ret4 = il1.Create(OpCodes.Ret);
        il1.Append(Ret4);

        var Foo_F_int32 = new MethodDefinition("F", MethodAttributes.Private | MethodAttributes.HideBySig, assembly.MainModule.TypeSystem.Void);
        t1.Methods.Add(Foo_F_int32);
        var il_Foo_F_int32 = Foo_F_int32.Body.GetILProcessor();
        var x5 = new ParameterDefinition("x", ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32);
        Foo_F_int32.Parameters.Add(x5);
        // if (x < 10)
        var Ldarg_16 = il_Foo_F_int32.Create(OpCodes.Ldarg_1);
        il_Foo_F_int32.Append(Ldarg_16);
        var Ldc_I47 = il_Foo_F_int32.Create(OpCodes.Ldc_I4, 10);
        il_Foo_F_int32.Append(Ldc_I47);
        il_Foo_F_int32.Append(il_Foo_F_int32.Create(OpCodes.Clt));
        var esp8 = il_Foo_F_int32.Create(OpCodes.Nop);
        il_Foo_F_int32.Append(il_Foo_F_int32.Create(OpCodes.Brfalse, esp8));
        //if body

// x = x + 1;
        var Ldarg_19 = il_Foo_F_int32.Create(OpCodes.Ldarg_1);
        il_Foo_F_int32.Append(Ldarg_19);
        var Ldc_I410 = il_Foo_F_int32.Create(OpCodes.Ldc_I4, 1);
        il_Foo_F_int32.Append(Ldc_I410);
        il_Foo_F_int32.Append(il_Foo_F_int32.Create(OpCodes.Add));
        var Starg_S11 = il_Foo_F_int32.Create(OpCodes.Starg_S, x5);
        il_Foo_F_int32.Append(Starg_S11);
        var ese12 = il_Foo_F_int32.Create(OpCodes.Nop);
        il_Foo_F_int32.Append(esp8);
        il_Foo_F_int32.Append(ese12);
        Foo_F_int32.Body.OptimizeMacros();
        var Ret13 = il_Foo_F_int32.Create(OpCodes.Ret);
        il_Foo_F_int32.Append(Ret13);

        assembly.Write(args[0]);
    }
}

By the way, the code above has been generated by this tool (https://cecilifier.me) (that can help you to learn about Mono.Cecil) with the following code:

class Foo
{
   void F(int x)
   {
     if (x < 10)
     {
         x = x + 1;
     }
   }
}
like image 194
Vagaus Avatar answered Dec 08 '25 09:12

Vagaus



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!