为什么MethodBody.GetILAsByteArray在不同的平台上返回不同的数组



我正在考虑实例方法Object.Equals(Object)。使用反射,可以将该方法的IL获取为字节数组,如下所示:

var mi = typeof(object).GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public);
var mb = mi.GetMethodBody();
var bytes = mb.GetILAsByteArray();

我有两台电脑:一台是运行Windows XP的32位电脑,另一台是使用Windows 7的64位电脑。这两台计算机都安装了.NET Framework的4.0.30319 SP1Rel版本。

在x86机器上,得到的阵列是:

[0]: 2
[1]: 3
[2]: 40
[3]: 122
[4]: 67
[5]: 0
[6]: 6
[7]: 42

不过,在x64机器上,我得到了这个:

[0]: 2
[1]: 3
[2]: 40
[3]: 123
[4]: 67
[5]: 0
[6]: 6
[7]: 42

第四个字节不同。

现在我知道mscorlib在64位平台上有两种风格。然而,ILDASM显示,这种方法的IL在不同口味和不同机器之间是相同的。在x64机器上,我将上面的代码瞄准了"任意CPU"one_answers"x86",但结果是一样的。

所以我的问题是,有人能解释这两台机器之间的差异吗?

更新

这是Object.Equals(Object):的C#和IL

public virtual bool Equals(object obj)
{
    return RuntimeHelpers.Equals(this, obj);
}
.maxstack  8
IL_0000:  ldarg.0
IL_0001:  ldarg.1
IL_0002:  call bool System.Runtime.CompilerServices.RuntimeHelpers::Equals(object, object)
IL_0007:  ret

只需自己编写方法并使用ildasm.exe查看即可更好地了解IL内容。使用View+Show bytes in ildasm查看字节值,请注意它们是十六进制的:

.method public hidebysig newslot virtual 
        instance bool  Equals(object obj) cil managed
// SIG: 20 01 02 1C
{
  // Method begins at RVA 0x2052
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  /* 02   |                  */ ldarg.0
  IL_0001:  /* 03   |                  */ ldarg.1
  IL_0002:  /* 28   | (0A)000010       */ call       bool [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::Equals(object,
                                                                                                                           object)
  IL_0007:  /* 2A   |                  */ ret
} // end of method Program::Equals

现在,您将看到IL_0003中的字节是方法标记的一部分,是其中最不重要的字节。请注意,我得到的值与您得到的值有很大不同。这是因为我刚刚写了一个非常小的程序,用很少的代码来测试它,它的清单非常小。反汇编程序非常有用,它实际上在元数据表中进行了查找,并用方法名替换了令牌,而不是只显示令牌值。

令牌是程序集清单的元数据表中的索引。当程序集中的代码发生更改并需要添加到表中时,这样的索引将更改。您可以在CLI规范ECMA335中了解更多关于它的信息。

不同的字节是引用RuntimeHelpers.Equals()的元数据标记的一部分。在重新编译模块时,不能保证元数据令牌是稳定的。这就是为什么绑定到其他程序集中的符号是按名称而不是按元数据标记进行的。

相关内容

  • 没有找到相关文章