ELEMENT_TYPE_MODIFIER의 조합
ELEMENT_TYPE_MODIFIER 조합을 알다가도 모르겠군요. ^^;
지난 글에서는 SNINativeMethodWrapper.MarshalConsumerInfo 메서드의 signature가 "SIG: 00 02 01 12 20 20 45 0f 11 30" 값이었고, 그중 0x45가 ELEMENT_TYPE_MODIFIER | ELEMENT_TYPE_PINNED의 조합인 것을 알 수 있었습니다.
그런데, .NET 2.0에 정의된 SNINativeMethodWrapper.MarshalConsumerInfo는 signature가 다릅니다.
.method private hidebysig static void MarshalConsumerInfo(class SNINativeMethodWrapper/ConsumerInfo consumerInfo,
valuetype SNI_CONSUMER_INFO* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) native_consumerInfo) cil managed
// SIG: 00 02 01 12 1C 20 39 0F 11 28
00 IMAGE_CEE_CS_CALLCONV_DEFAULT (static method)
02 # of arg(s)
01 ELEMENT_TYPE_VOID (return)
12 ELEMENT_TYPE_CLASS (1st arg type)
1C (1byte - type token)
20 ELEMENT_TYPE_CMOD_OPT
39 ????
0F ELEMENT_TYPE_PTR
11 ELEMENT_TYPE_VALUETYPE (2nd arg type)
28 (1byte - type token)
0x39라니...? ELEMENT_TYPE_MODIFIER의 값이 0x40이기 때문에 .NET 2.0 시절에는 ELEMENT_TYPE_MODIFIER로 분류되지도 않았다는 의미가 됩니다. 알수는 없지만, 억지로 조합해보면 다음과 같이 0x39를 만들 수 있습니다.
ELEMENT_TYPE_VALUETYPE = 0x11
ELEMENT_TYPE_PTR = 0x0f
== 20
ELEMENT_TYPE_U == 0x19
ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_PTR | ELEMENT_TYPE_U
그런데, ".NET 4.0 (x64)"에서는 또 다른 조합이 나옵니다.
.method private hidebysig static void MarshalConsumerInfo(class SNINativeMethodWrapper/ConsumerInfo consumerInfo,
valuetype Sni_Consumer_Info* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) native_consumerInfo) cil managed
SIG: 00 02 01 12 20 20 49 0F 11 38
0x49입니다. ELEMENT_TYPE_MODIFIER의 조합을 corhdr.h에서 보면,
ELEMENT_TYPE_MODIFIER = 0x40,
ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER, // sentinel for varargs
ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER,
ELEMENT_TYPE_R4_HFA = 0x06 | ELEMENT_TYPE_MODIFIER, // used only internally for R4 HFA types
ELEMENT_TYPE_R8_HFA = 0x07 | ELEMENT_TYPE_MODIFIER, // used only internally for R8 HFA types
0x49는 도저히 나올 수 없는 조합입니다. 게다가, 이번에 공개된 .NET 4.6 Preview의 corhdr.h에 보면 ELEMENT_TYPE_R4_HFA, ELEMENT_TYPE_R8_HFA는 아예 삭제된 것을 볼 수 있습니다.
// C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\Include\um\corhdr.h
ELEMENT_TYPE_MODIFIER = 0x40,
ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER, // sentinel for varargs
ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER,
도대체 어떻게 0x49가 나올 수 있을까 싶어 무작위로 검색해 보니, coreclr에 힌트가 나옵니다.
// https://github.com/dotnet/coreclr/blob/master/src/vm/compactlayoutwriter.h
178 enum CorElementTypeMDIL
179 {
180 ELEMENT_TYPE_NATIVE_VALUETYPE = 0x08 | ELEMENT_TYPE_MODIFIER
181 };
위의 값을 기반으로 만들어 보면, 0x49를 이렇게 만들어 볼 수 있습니다.
0x49 == ELEMENT_TYPE_MODIFIER | 0x08 | 0x01
== ELEMENT_TYPE_NATIVE_VALUETYPE | ELEMENT_TYPE_SENTINEL
00 IMAGE_CEE_CS_CALLCONV_DEFAULT (static method)
02 # of arg(s)
01 ELEMENT_TYPE_VOID (return)
12 ELEMENT_TYPE_CLASS (1st arg type)
20 (1byte - type token)
20 ELEMENT_TYPE_CMOD_OPT
49 ELEMENT_TYPE_NATIVE_VALUETYPE | ELEMENT_TYPE_SENTINEL
0F ELEMENT_TYPE_PTR
11 ELEMENT_TYPE_VALUETYPE (2nd arg type)
38 (1byte - type token)
물론, 위의 가정은 어디까지나 제 개인적인 가정입니다. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]