Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Off by 256 error in generated IL code for label.  #21799

@manjaroman2

Description

@manjaroman2

The code:

public static OneParameter<ulong, Item> GenerateILGetRankIL()
{
    DynamicMethod dynamicMethod = new(
        "getRank",
        typeof(ulong),
        new[] { typeof(Item) }
    );

    ILGenerator il = dynamicMethod.GetILGenerator();
    Label[] labels = new Label[8];
    for (int i = 0; i < labels.Length; i++) labels[i] = il.DefineLabel();

    // ulong num = 0uL;
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Conv_I8);
    il.Emit(OpCodes.Stloc_0);
    // if (item == null)
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Brtrue_S, labels[0]);
    // return num;
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ret);
    // ulong num2 = 9223372036854775808uL;
    il.MarkLabel(labels[0]);
    il.Emit(OpCodes.Ldc_I8, -9223372036854775808);
    il.Emit(OpCodes.Stloc_1);
    // int num3 = 64;
    il.Emit(OpCodes.Ldc_I4_S, 64);
    il.Emit(OpCodes.Stloc_2);


    // if (item.IsUnique)
    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Callvirt, Item__GetUnique, null);
    il.Emit(OpCodes.Brfalse_S, labels[1]);
    // num |= num2;
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Or);
    il.Emit(OpCodes.Stloc_0);
    // num2 >>= 1;
    il.MarkLabel(labels[1]);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Stloc_1);
    // num3--;
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Stloc_2);


    // num |= num2 >> (int)(6 - item.Rarity);
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_6);
    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Callvirt, Item__GetRarity, null);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Ldc_I4_S, 63);
    il.Emit(OpCodes.And);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Or);
    il.Emit(OpCodes.Stloc_0);
    // num2 >>= 6;
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_6);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Stloc_1);
    // num3 -= 6;
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Ldc_I4_6);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Stloc_2);


    // num |= num2 >> 5 - item.Tier.Id;
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_5);
    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Callvirt, Item__GetTier, null);
    il.Emit(OpCodes.Stloc_3);
    il.Emit(OpCodes.Ldloca_S, 3);
    il.EmitCall(OpCodes.Callvirt, TierId__GetId, null);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Ldc_I4_S, 63);
    il.Emit(OpCodes.And);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Or);
    il.Emit(OpCodes.Stloc_0);
    // num2 >>= 5;
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_5);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Stloc_1);
    // num3 -= 5;
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Ldc_I4_5);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Stloc_2);


    // num |= num2 >> (int)item.Type;
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Callvirt, Item__GetType, null);
    il.Emit(OpCodes.Ldc_I4_S, 63);
    il.Emit(OpCodes.And);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Or);
    // num2 >>= 11;
    il.Emit(OpCodes.Stloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldc_I4_S, 11);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Stloc_1);
    // num3 -= 11;
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Ldc_I4_S, 11);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Stloc_2);
    // num3 -= 26;
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Ldc_I4_S, 26);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Stloc_2);


    // string subtypeCode = item.SubtypeCode;
    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Callvirt, Item__GetSubtypeCode, null);
    il.Emit(OpCodes.Stloc_S, 4);
    // (no C# code)
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Stloc_S, 5);
    // 	foreach (int num4 in subtypeCode)
    // 	{
    // 		int num5 = num4;
    // 		if (num5 < 65)
    // 		{
    // 			continue;
    // 		}
    // 		if (num4 > 65 + num3)
    // 		{
    // 			if (num5 > 96 && num5 < 123)
    // 			{
    // 				num ^= num2 >> num4 - 97 + num3;
    // 			}
    // 		}
    // 		else
    // 		{
    // 			num ^= num2 >> num4 - 65;
    // 		}
    // 	}
    il.Emit(OpCodes.Br_S, labels[7]);
    MelonLogger.Msg($"MarkLabel 2 {il.ILOffset}"); 
    il.MarkLabel(labels[2]);
    MelonLogger.Msg($"MarkLabel 2 {il.ILOffset}"); 
    il.Emit(OpCodes.Ldloc_S, 4);
    il.Emit(OpCodes.Ldloc_S, 5);
    il.EmitCall(OpCodes.Callvirt,String__GetChars, null);
    il.Emit(OpCodes.Stloc_S, 6);
    // int num5 = num4;
    il.Emit(OpCodes.Ldloc_S, 6);
    il.Emit(OpCodes.Stloc_S, 7);
    // if (num5 < 65)
    il.Emit(OpCodes.Ldloc_S, 7);
    il.Emit(OpCodes.Ldc_I4_S, 65);
    il.Emit(OpCodes.Bge_S, labels[4]);
    // if (num5 > 96 && num5 < 123)
    il.Emit(OpCodes.Br_S, labels[6]);
    // loop start (head: IL_00b0)
    il.MarkLabel(labels[3]);
    il.Emit(OpCodes.Ldloc_S, 7);
    il.Emit(OpCodes.Ldc_I4_S, 96);
    il.Emit(OpCodes.Ble_S, labels[6]);
    il.Emit(OpCodes.Ldloc_S, 7);
    il.Emit(OpCodes.Ldc_I4_S, 123);
    MelonLogger.Msg($"Blt_S {il.ILOffset}"); 
    il.Emit(OpCodes.Blt_S, labels[5]);
    MelonLogger.Msg($"Blt_S {il.ILOffset}"); 
    
    // if (num4 > 65 + num3)
    il.Emit(OpCodes.Br_S, labels[6]);
    il.MarkLabel(labels[4]);
    il.Emit(OpCodes.Ldloc_S, 6);
    il.Emit(OpCodes.Ldc_I4_S, 65);
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Bgt_S, labels[3]);
    // end loop
    // num ^= num2 >> num4 - 65;
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldloc_S, 6);
    il.Emit(OpCodes.Ldc_I4_S, 65);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Ldc_I4_S, 63);
    il.Emit(OpCodes.And);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Xor);
    il.Emit(OpCodes.Stloc_0);
    // num ^= num2 >> num4 - 97 + num3;
    il.Emit(OpCodes.Br_S, labels[6]);
    MelonLogger.Msg($"MarkLabel 5 {il.ILOffset}"); 
    il.MarkLabel(labels[5]);
    MelonLogger.Msg($"MarkLabel 5 {il.ILOffset}"); 
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_1);
    il.Emit(OpCodes.Ldloc_S, 6);
    il.Emit(OpCodes.Ldc_I4_S, 97);
    il.Emit(OpCodes.Sub);
    il.Emit(OpCodes.Ldloc_2);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ldc_I4_S, 63);
    il.Emit(OpCodes.And);
    il.Emit(OpCodes.Shr_Un);
    il.Emit(OpCodes.Xor);
    il.Emit(OpCodes.Stloc_0);
    // (no C# code)
    il.MarkLabel(labels[6]);
    il.Emit(OpCodes.Ldloc_S, 5);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Stloc_S, 5);
    // return num;
    il.MarkLabel(labels[7]);
    il.Emit(OpCodes.Ldloc_S, 5);
    il.Emit(OpCodes.Ldloc_S, 4);
    il.EmitCall(OpCodes.Callvirt, String__GetLength, null);
    MelonLogger.Msg($"Blt_S {il.ILOffset}"); 
    il.Emit(OpCodes.Blt_S, labels[2]);
    MelonLogger.Msg($"Blt_S {il.ILOffset}"); 
    // end loop


    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ret);

    OneParameter<ulong, Item> del =
        (OneParameter<ulong, Item>)dynamicMethod.CreateDelegate(typeof(OneParameter<ulong, Item>));
    return del;
    // OneParameter<ulong, Item> getRankIL =
    //     (OneParameter<ulong, Item>)dynamicMethod.CreateDelegate(typeof(OneParameter<ulong, Item>));
    // return del;
}

The console log:

[14:05:20.761] [MoreQOD] MarkLabel 2 169
[14:05:20.763] [MoreQOD] MarkLabel 2 169
[14:05:20.764] [MoreQOD] Blt_S 235
[14:05:20.764] [MoreQOD] Blt_S 237
[14:05:20.765] [MoreQOD] MarkLabel 5 277
[14:05:20.766] [MoreQOD] MarkLabel 5 277
[14:05:20.767] [MoreQOD] Blt_S 328
[14:05:20.768] [MoreQOD] Blt_S 330
[14:05:20.770] [MoreQOD] [ERROR] System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:getRank (Death.Items.Item): IL_0148: blt.s     IL_01a9


  at (wrapper managed-to-native) System.Delegate.CreateDelegate_internal(System.Type,object,System.Reflection.MethodInfo,bool)
  at System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, System.Boolean throwOnBindFailure, System.Boolean allowClosed) [0x002f0] in <9aad1b3a47484d63ba2b3985692d80e9>:0
  at System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method) [0x00000] in <9aad1b3a47484d63ba2b3985692d80e9>:0
  at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00029] in <9aad1b3a47484d63ba2b3985692d80e9>:0
  at MQOD.Sort.GenerateILGetRankIL () [0x00957] in <1efc024047cc4f579f5b6f749046551d>:0
  at MQOD.SortShop.sortShop () [0x00028] in <1efc024047cc4f579f5b6f749046551d>:0
  at MQOD.MQOD.OnLateUpdate () [0x0037a] in <1efc024047cc4f579f5b6f749046551d>:0
  at MelonLoader.MelonEvent+<>c.<Invoke>b__1_0 (MelonLoader.LemonAction x) [0x00000] in <6425afb6ac6a429aaf770255d2f7de57>:0
  at MelonLoader.MelonEventBase`1[T].Invoke (System.Action`1[T] delegateInvoker) [0x00018] in <6425afb6ac6a429aaf770255d2f7de57>:0

I have tracked the issue down to that last call of Blt_S, because we can see from the error that the offending code happens at offset IL_0148 which corresponds to 328 in decimal in the log:

...
    il.Emit(OpCodes.Blt_S, labels[2]);
...

The generated IL uses the address IL_01a9 for labels[2] but from my logging I can see that MarkLabel(labels[2]) happens at ILOffset '169' decimal or 'A9' in hex. So IL_01a9 is off by exactly 100 in hex or 256 in decimal. So the generated IL should be "IL_0148: blt.s IL_00a9" and not "IL_0148: blt.s IL_01a9", right?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions