【问题标题】:Mono.Cecil instruction labels resolvingMono.Cecil 指令标签解析
【发布时间】:2015-11-13 00:16:06
【问题描述】:

我正在使用 Mono.Cecil 在属性设置器中注入一些指令,并且在注入 Brfalse_s 指令时出现奇怪的错误。这是代码,很简短。

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_sIL_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

【问题讨论】:

  • 为什么是stloc+ldloc?如果您只是直接使用结果,您可以省去添加变量和所有内容的工作。是否有某些原因为什么您不只使用单个 brnull 而不是这些比较?您是否只是发出最初由 C# 编译器生成的代码(显然是在调试中)?
  • 我不是 IL 专家 :) 我刚开始学习它,我编写 C# 代码,我使用 ILSpy 来查看 IL 输出,然后他们复制它 :D 我该如何使用直接结果?
  • 如果我正确理解你的代码,你想要做的基本上是if (arg1 != null) return;,对吧?这可以通过简单的ldarg.1 后跟brnull theretlabel 来完成。即使您决定保留原始代码,IL 也是基于堆栈的,因此当cgt.un 返回一个值时,它会将其返回到(虚拟)堆栈——brfalse 可以立即使用它,而无需将其存储在多变的。最初的nop 也是不必要的 - 编译器使用它来允许调试器进行代码注入,但您不需要它。
  • 是的,我了解它是如何工作的(堆栈机器),但我只是想尝试用Mono.Cecil 注入一些东西,看看它是如何工作的。这就是为什么我刚刚重现了 C# 编译器生成的内容(调试)。我知道Nop 不是必需的,它的目的是什么。我不知道这个东西在分支指令中有偏移,而_S 意味着短跳转。我刚刚看到 C# 编译器为跳转生成它,所以我也做了同样的事情:D 非常感谢您的快速帮助和详细解释:)。

标签: c# mono.cecil


【解决方案1】:

这应该很明显 - 你不能使用brfalse.s 进行跳远:)

这与try无关,问题是你的跳跃目标太远了。请改用brfalse

注意目标标签如何变为0x0011 而不是0x0211 - brfalse.s(以及所有其他.s 跳转)将单个字节作为跳转偏移量,因此其余的偏移量被切断。

当然,brfalse 有点大,但这并不重要——它只会夸大已经相当膨胀的 IL 代码。无论您在此处做什么,JIT 编译器都会使用最有效的跳转。

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

【讨论】:

  • 我不敢相信。我没有意识到.s 是关于代码长度的。感谢您的快速回答,我花了一整天的时间试图弄清楚这一点。
猜你喜欢
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多