【问题标题】:Invalid IL code generated生成了无效的 IL 代码
【发布时间】:2017-12-29 00:40:11
【问题描述】:

我正在尝试将两种方法合并在一起(一种来自我的项目,一种来自 dll)并将它们写入 dll。原始代码如下所示:

 .method public hidebysig static class Storage.DataMap 
    Create() cil managed 
  {
    .maxstack 8

    // [22 7 - 22 70]
    IL_0000: call         unmanaged stdcall native int Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
    IL_0005: newobj       instance void Storage.DataMap::.ctor(native int)
    IL_000a: ret          

  } // end of method DataMap::Create

我想在这段代码中添加一个简单的 Console.WriteLine,我最终得到以下内容:(来自反编译器)

  .method public hidebysig static class Storage.DataMap 
    Create() cil managed 
  {
    .maxstack 8

    // [22 7 - 22 44]
    IL_0000: ldstr        "Hello World"
    IL_0005: call         void [mscorlib]System.Console::WriteLine(string)

    // [23 7 - 23 70]
    IL_000a: call         unmanaged stdcall native int Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
    IL_000f: newobj       instance void Storage.DataMap::.ctor(native int)
    IL_0014: ret          

  } // end of method DataMap::Create

我的反编译器无法反编译(dotPeek),所以我假设我生成的 IL 无效。但是,我不确定我生成的 IL 有什么问题。

我使用 dnlib 和 C# 来获取方法的 IL 代码,然后将两个代码块连接在一起(我剥离了 nopret 语句(最后一个除外))。为了重新编译我使用 ModuleDef#Write(String) 函数的代码,我在编写自己的 IL 语句时已经成功,但在合并已经存在的语句时却没有。

(下面的IL都是从控制台打印出来的,不是反编译的)
原始第 1 部分 IL:

IL_0000: nop
IL_0001: ldstr "Hello World"
IL_0006: call System.Void System.Console::WriteLine(System.String)
IL_000B: nop
IL_000C: ret

原版第 2 部分 IL:

IL_0000: call System.IntPtr Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_0005: newobj System.Void Storage.DataMap::.ctor(System.IntPtr)
IL_000A: ret

合并 IL:

IL_0001: ldstr "Hello World"
IL_0006: call System.Void System.Console::WriteLine(System.String)
IL_0000: call System.IntPtr Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_0005: newobj System.Void Storage.DataMap::.ctor(System.IntPtr)
IL_000A: ret

【问题讨论】:

  • C# 级别太高? :-) 无论如何,我不得不想知道为什么 nop 首先会在那里。对于您编译器来说,这似乎是一个容易删除的候选者,因此可能出于某种原因需要它。
  • 这似乎没有什么区别,我在反编译器错误时尝试的第一件事是删除nop,但这并没有帮助。 @paxdiablo
  • 实际上,合并后的 IL 的标签都搞砸了 (1,6,0,5,a)。会不会是个问题?
  • 如果您使用的是 dnlib,您需要在您的问题中包含一个很好的 minimal reproducible example,以准确显示您如何使用它。您在上面显示的只是 data,在要求人们帮助您调试 code 时几乎没有用处。
  • 如果 IL 无效,那么 peverify 应该能够告诉你哪里出了问题。老实说,您确实需要显示用于进行合并的代码。一个可能的问题是您正在尝试加载必须在模块元数据中定义的字符串。您是否正确更新了目标程序集的元数据以包含新的元数据令牌?您需要更改方法的 IL 和目标模块的元数据。

标签: c# cil dnlib


【解决方案1】:

我解决了自己的问题。正如多个人在 cmets 中正确指出的那样,IL 是正确的。该问题与我的代码或生成的 IL 无关,而是与反编译器 dotPeek 有关。

发生的情况如下:我第一次生成 DLL,但 IL 错误(它有 2 个返回语句),用 dotPeek 反编译它,发现 IL 格式错误。我再次这样做了,但使用了正确的 IL(只有 1 个返回语句)并删除了旧的 DLL,将新的 DLL 重命名为旧的,删除的,一个。但是 DotPeek 不喜欢这样,它会显示更新后的 IL,但不会显示更新后的代码。

在多次重新启动并删除/重新添加程序集后,我发现情况确实如此。 dnSpy 似乎比 dotPeek 工作得更好,所以我将来会使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多