2015-11-12 70 views
3

我正在使用Mono.Cecil在属性setter中注入一些指令,注入Brfalse_s指令时我有奇怪的错误。这里是代码,简短。Mono.Cecil指令标签解析

private void InjectNullProtection(PropertyDefinition property) 
{ 
    IList<Instruction> instructions = property.SetMethod.Body.Instructions; 

     Instruction first = instructions.First(); 

     if (!property.SetMethod.Body.Variables.Any(v => v.VariableType.FullName == GetTypeReference(typeof(bool)).FullName)) 
     { 
      property.SetMethod.Body.Variables.Add(new VariableDefinition(GetTypeReference(typeof(bool)))); 
     } 

     ILProcessor processor = property.SetMethod.Body.GetILProcessor(); 
     Instruction ret = instructions.Single(i => i.OpCode.Code == Code.Ret); 

     processor.InsertBefore(first, processor.Create(OpCodes.Nop)); 
     processor.InsertBefore(first, processor.Create(OpCodes.Ldarg_1)); 
     processor.InsertBefore(first, processor.Create(OpCodes.Ldnull)); 
     processor.InsertBefore(first, processor.Create(OpCodes.Cgt_Un)); 
     processor.InsertBefore(first, processor.Create(OpCodes.Stloc_0)); 
     processor.InsertBefore(first, processor.Create(OpCodes.Ldloc_0)); 

     processor.InsertBefore(first, processor.Create(OpCodes.Brfalse_S, ret)); 
} 

如果目标设置器没有任何try/catch块,则一切正常。但是如果在setter中有try/catch块,则对于Brfalse_s指令的目标标签是错误的,而不是Ret指令标签,它具有来自try块之一的指令标签。下面是示例:

IL_0000: nop 
IL_0001: ldarg.1 
IL_0002: ldnull 
IL_0003: cgt.un 
IL_0005: stloc.0 
IL_0006: ldloc.0 
IL_0007: brfalse.s IL_0037 

IL_0009: nop 
IL_000a: ldarg.0 
IL_000b: ldstr "Name" 
IL_0010: callvirt instance void WpfApplication2.Observable1::OnPropertyChanging(string) 
IL_0015: nop 
IL_0016: ldarg.0 
IL_0017: ldarg.1 
IL_0018: stfld string WpfApplication2.Observable1::'<Name>k__BackingField' 
IL_001d: ldarg.0 
IL_001e: ldstr "Name" 
IL_0023: callvirt instance void WpfApplication2.Observable1::OnPropertyChanged(string) 
IL_0028: nop 
IL_0029: nop 
IL_002a: ldarg.0 
IL_002b: ldstr "FullName" 
IL_0030: callvirt instance void WpfApplication2.Observable1::OnPropertyChanged(string) 
IL_0035: nop 
IL_0036: nop 

IL_0037: ret 

在这里你可以看到Brfalse_s具有IL_0037目标标签,这是正确的。但在下一个例子中,出现了一些问题。

IL_0000: nop 
IL_0001: ldarg.1 
IL_0002: ldnull 
IL_0003: cgt.un 
IL_0005: stloc.0 
IL_0006: ldloc.0 
IL_0007: brfalse.s IL_0011 

IL_0009: nop 
.try 
{ 
    IL_000a: nop 
    IL_000b: ldarg.0 
    IL_000c: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 

    IL_0011: ldarg.0 
    IL_0012: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0018: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_001d: callvirt instance void WpfApplication2.Observable2::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_0022: nop 
    IL_0023: ldarg.0 
    IL_0024: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0029: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_002e: ldarg.0 
    IL_002f: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0035: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_003a: callvirt instance void WpfApplication2.Observable3::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_003f: nop 
    IL_0040: ldarg.0 
    IL_0041: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0046: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_004b: callvirt instance class WpfApplication2.Observable4 WpfApplication2.Observable3::get_Observable4() 
    IL_0050: ldarg.0 
    IL_0051: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3Observable4PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0057: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_005c: callvirt instance void WpfApplication2.Observable4::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_0061: nop 
    IL_0062: ldarg.0 
    IL_0063: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0068: ldarg.0 
    IL_0069: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_006f: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_0074: callvirt instance void WpfApplication2.Observable2::remove_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_0079: nop 
    IL_007a: ldarg.0 
    IL_007b: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0080: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_0085: ldarg.0 
    IL_0086: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_008c: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_0091: callvirt instance void WpfApplication2.Observable3::remove_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_0096: nop 
    IL_0097: leave.s IL_009e 
} // end .try 
catch [mscorlib]System.NullReferenceException 
{ 
    IL_0099: pop 
    IL_009a: nop 
    IL_009b: nop 
    IL_009c: leave.s IL_009e 
} // end handler 

IL_009e: nop 
IL_009f: nop 
.try 
{ 
    IL_00a0: nop 
    IL_00a1: ldarg.0 
    IL_00a2: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_00a7: ldarg.0 
    IL_00a8: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_00ae: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_00b3: callvirt instance void WpfApplication2.Observable2::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_00b8: nop 
    IL_00b9: ldarg.0 
    IL_00ba: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_00bf: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_00c4: ldarg.0 
    IL_00c5: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2Observable3PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_00cb: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_00d0: callvirt instance void WpfApplication2.Observable3::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_00d5: nop 
    IL_00d6: ldarg.0 
    IL_00d7: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_00dc: ldarg.0 
    IL_00dd: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_00e3: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_00e8: callvirt instance void WpfApplication2.Observable2::remove_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_00ed: nop 
    IL_00ee: leave.s IL_00f5 
} // end .try 
catch [mscorlib]System.NullReferenceException 
{ 
    IL_00f0: pop 
    IL_00f1: nop 
    IL_00f2: nop 
    IL_00f3: leave.s IL_00f5 
} // end handler 

IL_00f5: nop 
IL_00f6: nop 
IL_00f7: ldarg.0 
IL_00f8: ldstr "Observable2" 
IL_00fd: callvirt instance void WpfApplication2.Observable1::OnPropertyChanging(string) 
IL_0102: nop 
IL_0103: ldarg.0 
IL_0104: ldarg.1 
IL_0105: stfld class WpfApplication2.Observable2 WpfApplication2.Observable1::'<Observable2>k__BackingField' 
IL_010a: nop 
.try 
{ 
    IL_010b: nop 
    IL_010c: ldarg.0 
    IL_010d: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0112: ldarg.0 
    IL_0113: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0119: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_011e: callvirt instance void WpfApplication2.Observable2::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_0123: nop 
    IL_0124: ldarg.0 
    IL_0125: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_012a: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_012f: ldarg.0 
    IL_0130: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0136: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_013b: callvirt instance void WpfApplication2.Observable3::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_0140: nop 
    IL_0141: ldarg.0 
    IL_0142: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0147: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_014c: callvirt instance class WpfApplication2.Observable4 WpfApplication2.Observable3::get_Observable4() 
    IL_0151: ldarg.0 
    IL_0152: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3Observable4PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0158: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_015d: callvirt instance void WpfApplication2.Observable4::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_0162: nop 
    IL_0163: ldarg.0 
    IL_0164: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0169: ldarg.0 
    IL_016a: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_0170: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_0175: callvirt instance void WpfApplication2.Observable2::add_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_017a: nop 
    IL_017b: ldarg.0 
    IL_017c: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_0181: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_0186: ldarg.0 
    IL_0187: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Observable4Name_OnObservable2Observable3PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_018d: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_0192: callvirt instance void WpfApplication2.Observable3::add_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_0197: nop 
    IL_0198: leave.s IL_019f 
} // end .try 
catch [mscorlib]System.NullReferenceException 
{ 
    IL_019a: pop 
    IL_019b: nop 
    IL_019c: nop 
    IL_019d: leave.s IL_019f 
} // end handler 

IL_019f: nop 
IL_01a0: nop 
.try 
{ 
    IL_01a1: nop 
    IL_01a2: ldarg.0 
    IL_01a3: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_01a8: ldarg.0 
    IL_01a9: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_01af: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_01b4: callvirt instance void WpfApplication2.Observable2::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_01b9: nop 
    IL_01ba: ldarg.0 
    IL_01bb: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_01c0: callvirt instance class WpfApplication2.Observable3 WpfApplication2.Observable2::get_Observable3() 
    IL_01c5: ldarg.0 
    IL_01c6: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2Observable3PropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_01cc: newobj instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int) 
    IL_01d1: callvirt instance void WpfApplication2.Observable3::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler) 
    IL_01d6: nop 
    IL_01d7: ldarg.0 
    IL_01d8: call instance class WpfApplication2.Observable2 WpfApplication2.Observable1::get_Observable2() 
    IL_01dd: ldarg.0 
    IL_01de: ldftn instance void WpfApplication2.Observable1::FullName_Observable2Observable3Name_OnObservable2PropertyChanging(object, class [System]System.ComponentModel.PropertyChangedEventArgs) 
    IL_01e4: newobj instance void [System]System.ComponentModel.PropertyChangingEventHandler::.ctor(object, native int) 
    IL_01e9: callvirt instance void WpfApplication2.Observable2::add_PropertyChanging(class [System]System.ComponentModel.PropertyChangingEventHandler) 
    IL_01ee: nop 
    IL_01ef: leave.s IL_01f6 
} // end .try 
catch [mscorlib]System.NullReferenceException 
{ 
    IL_01f1: pop 
    IL_01f2: nop 
    IL_01f3: nop 
    IL_01f4: leave.s IL_01f6 
} // end handler 

IL_01f6: nop 
IL_01f7: ldarg.0 
IL_01f8: ldstr "Observable2" 
IL_01fd: callvirt instance void WpfApplication2.Observable1::OnPropertyChanged(string) 
IL_0202: nop 
IL_0203: nop 
IL_0204: ldarg.0 
IL_0205: ldstr "FullName" 
IL_020a: callvirt instance void WpfApplication2.Observable1::OnPropertyChanged(string) 
IL_020f: nop 
IL_0210: nop 
IL_0211: ret 

这里,Brfalse_sIL_0011为目标标签,而不是IL_0211

+1

为什么'stloc' +'ldloc'?如果你直接使用了结果,你可以通过添加一个变量来节省工作量。你有什么理由不使用一个'brnull'而不是那些比较?你只是发出最初由C#编译器生成的代码(显然是在调试中)? – Luaan

+0

我不是IL专家:)我刚开始学习它,并且我编写C#代码,并且使用ILSpy来查看IL输出,并将它们复制到D:我如何直接使用结果? –

+0

如果我正确理解你的代码,你想要做的事情基本上是'if(arg1!= null)return;',对吧?这可以通过简单的'ldarg.1'完成,后面跟'brnull theretlabel'。即使你决定保留你的原始代码,IL也是基于堆栈的,所以当'cgt.un'返回一个值时,它将它返回到(虚拟)堆栈 - 它可以立即被'brfalse'使用而不用存储它在一个变量中。最初的'nop'也是不必要的 - 编译器使用它来允许调试器注入代码,但你并不需要。 – Luaan

回答

5

这应该是显而易见的 - 你不能长期跳:)

这有什么好做的try使用brfalse.s,问题是,你的跳转目标简直是太过分了。改为使用brfalse

注意目标标签是如何成为0x0011,而不是0x0211 - brfalse.s(和所有其他.s跳跃)取一个字节为跳转偏移,所以偏移的其余部分被切断。

当然,brfalse是有点大,但这并不重要 - 它只是膨胀了IL代码,无论如何已经相当夸张。无论你在这里做什么,JIT编译器都将使用最有效的跳转。

发出自定义IL时,必须非常小心 - 没有任何处理,只需将字节写入流。在进行发射时,你不会得到大量的错误,几乎所有你做错的事情都会导致运行时错误。

+0

我简直不敢相信。我没有意识到'.s'是关于代码长度的。感谢您快速回答,我花了整整一天的时间试图弄清楚这一点。 –