不同类型在 CIL 中具有相同的签名
Different types have same signatures in CIL
我在 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
是从哪里来的)。
让我们尝试根据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)。然后 "compressed" 进入单字节 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 中显示的签名完全相同的签名。
我在 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
是从哪里来的)。
让我们尝试根据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)。然后 "compressed" 进入单字节 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 中显示的签名完全相同的签名。