不同类型在 CIL 中具有相同的签名

Posted

技术标签:

【中文标题】不同类型在 CIL 中具有相同的签名【英文标题】:Different types have same signatures in CIL 【发布时间】:2015-03-04 14:33:43 【问题描述】:

我在 CIL 中定义了一个字段,如下所示:

.field public int32 modopt(void*) fld

我把它编译成一个程序集。现在我把它改成:

.field public int32 modopt(int16) fld

ILDASM 现在怎么可能报告(当显示为十六进制时)两个这两个字段?

Field #1 (04000001)
-------------------------------------------------------
    Field Name: fld (04000001)
    Flags     : [Public]  (00000006)
    CallCnvntn: [FIELD]
    Field type:  CMOD_OPT 1b000001 I4
    Signature : 06 20 06 08 

此代码查找完全相同的两个字段(实际上我创建了第二个字段以匹配报告的签名)。签名显然与第二个字段匹配,但第一个字段的签名应该是这样的:06 20 0f 01 08!我在这里错过了什么?

编辑:

C# 不能发出这种类型的字段,抛出关于自定义类型修饰符不支持的指针和数组类型的异常,因此这显然解决了签名不匹配的问题。但是为什么 ILDASM 允许创建无法反编译的无效签名的问题仍然存在。

编辑#2:

似乎 ILASM 实际上正在创建正确的 IL,我上次错过的十六进制转储有所不同:

//the first assembly
TypeSpec #1 (1b000001)
-------------------------------------------------------
    TypeSpec : Ptr Void
    Signature: 0f 01 

//the second assembly
TypeSpec #1 (1b000001)
-------------------------------------------------------
    TypeSpec : I2
    Signature: 06 

所以在 ILDASM 十六进制转储中只有一个错误报告了错误的成员签名(尽管我想知道错误签名中的 06 来自哪里)。

【问题讨论】:

问一个显而易见的问题:是什么让你认为它应该是06 20 0f 01 08?是否有细分/参考? @Marc 我查看了 CLI 的 ECMA。 modopt的元素类型为20,指针的元素类型为0f,void为01。所以,把所有这些放在一起,modopt(void*) 的签名应该是20 0f 0106 是字段 callconv,08 是 int32)。 这是 C# 吗?我看到了 void* ! @niceman 不,它是 CIL @niceman void* 在 C# 中与在 C++ 中一样有效。它也可以是任意数量的其他语言(包括手动编写的 CIL)。 【参考方案1】:

让我们尝试基于the specification手动构建字段签名。首先,字段签名在 §II.23.2.4 中定义。对于我们使用一个自定义修饰符的情况,它将是:

FIELD CustomMod Type

由于FIELD被定义为0x06,我们有:

06 CustomMod Type

我们的自定义修饰符是modopt,所以我们得到(基于§II.23.2.7):

06 CMOD_OPT TypeDefOrRefOrSpecEncoded Type

CMOD_OPT 是 0x20 (§II.23.1.16):

06 20 TypeDefOrRefOrSpecEncoded Type

我们想要引用TypeSpec 0x1b000001,它被编码为 0b110(10 代表 TypeSpec,1 代表 0x000001,§II.23.2.8)。然后将其“压缩”成单字节 0x06 (§II.23.2):

06 20 06 Type

最后,类型为int32,即ELEMENT_TYPE_I4 = 0x08(§II.23.2.12 和§II.23.1.16):

06 20 06 08

所以我们得到的签名与 ILDasm 中显示的签名完全相同。

【讨论】:

谢谢,这更有意义。我认为它应该是类型签名,而不是类型令牌,所以我误解了 ILDasm 的结果。

以上是关于不同类型在 CIL 中具有相同的签名的主要内容,如果未能解决你的问题,请参考以下文章

C#中具有相同名称和签名但返回类型不同的方法

TypeScript 具有相同参数的多种返回类型

如何在 CIL 中的堆栈上处理不同的类型

C#委托初学

为啥不能用相同的签名声明两个方法,即使它们的返回类型不同? [复制]

为啥我不能将 QWebsocket::error SIGNAL 连接到 lambda 或具有相同签名的任何其他 SLOT 类型? QT5.9 [重复]