生成了无效的 IL 代码
Invalid IL code generated
我正在尝试将两种方法合并在一起(一种方法来自我的项目,一种来自 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 有什么问题。
我在 C# 中使用 dnlib
来获取方法的 IL 代码,然后将两个代码块连接在一起(我删除了 nop
和 ret
语句(除了最后一个))。要重新编译我使用 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
我解决了自己的问题。正如多个人在评论中正确指出的那样,IL 是正确的。该问题与我的代码或生成的 IL 无关,但与反编译器 dotPeek 有关。
发生的事情如下:我第一次生成DLL,但是IL是错误的(它有2个return语句),用dotPeek反编译它,发现IL格式错误。我又做了一次,但使用了正确的 IL(只有 1 个 return 语句)并删除了旧的 DLL,将新的 DLL 重命名为旧的、已删除的 DLL。但是 DotPeek 不喜欢这样,它会显示更新的 IL,但不会显示更新的代码。
在多次重新启动和 removing/re-adding 程序集之后,我发现情况确实如此。 dnSpy 似乎比 dotPeek 工作得更好,所以我将来会使用它。
我正在尝试将两种方法合并在一起(一种方法来自我的项目,一种来自 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 有什么问题。
我在 C# 中使用 dnlib
来获取方法的 IL 代码,然后将两个代码块连接在一起(我删除了 nop
和 ret
语句(除了最后一个))。要重新编译我使用 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
我解决了自己的问题。正如多个人在评论中正确指出的那样,IL 是正确的。该问题与我的代码或生成的 IL 无关,但与反编译器 dotPeek 有关。
发生的事情如下:我第一次生成DLL,但是IL是错误的(它有2个return语句),用dotPeek反编译它,发现IL格式错误。我又做了一次,但使用了正确的 IL(只有 1 个 return 语句)并删除了旧的 DLL,将新的 DLL 重命名为旧的、已删除的 DLL。但是 DotPeek 不喜欢这样,它会显示更新的 IL,但不会显示更新的代码。
在多次重新启动和 removing/re-adding 程序集之后,我发现情况确实如此。 dnSpy 似乎比 dotPeek 工作得更好,所以我将来会使用它。