In Disassembling .Net Notes- Method Signatures Part 1, I discussed the MethodDefSig and barely mentioned the MethodRefSig - so here is the detail on MethodRefSig.
From Partition II, page 154 and 155:
A MethodRefSig is indexed by the MemberRef.Signature column. This provides the call site Signature for a method. Normally, this call site Signature shall match exactly the Signature specified in the definition of the target method. For example, if a method Foo is defined that takes two unsigned int32s and returns void; then any call site shall index a signature that takes exactly two unsigned int32s and returns void. In this case, the
syntax diagram for a MethodRefSig is identical with that for a MethodDefSig – see §23.2.1 Partition II 155 The Signature at a call site differs from that at its definition, only for a method with the VARARG calling convention. In this case, the call site Signature is extended to include info about the extra VARARG arguments (for example, corresponding to the “...” in C syntax).
HASTHIS = 0x20, used to encode the keyword instance in the calling convention
EXPLICITTHIS = 0x40, used to encode the keyword explicit in the calling convention
VARARG = 0x5, used to encode the keyword vararg in the calling convention
SENTINEL = 0x41 (§23.1.16), used to encode “...” in the parameter list
The first byte of the Signature holds bits for HASTHIS, EXPLICITTHIS, and the calling convention VARARG. These are ORed together.
ParamCount is an integer that holds the number of parameters (0 or more). It can be any number between 0 and 0x1FFFFFFF The compiler compresses it too (see Partition II Metadata Validation) – before storing into the 'blob' (ParamCount counts just the method parameters – it does not include the method’s return type)
The RetType item describes the type of the method’s return value (§23.2.11)
The Param item describes the type of each of the method’s parameters. There shall be ParamCount instances of the Param item. The Param item describes the type of each of the method’s parameters. There shall be ParamCount instances of the Param item.This starts just like the MethodDefSig for a VARARG method (§23.2.1). But then a SENTINEL
token is appended, followed by extra Param items to describe the extra VARARG arguments. Note that the ParamCount item shall indicate the total number of Param items in the Signature – before and after the SENTINEL byte (0x41). In the unusual case that a call site supplies no extra arguments, the signature shall not include a SENTINEL (this is the route shown by the lower arrow that bypasses SENTINEL and goes to the end of the MethodRefSig definition).
So far the method signatures up to this point have been the signatures from their declarations (hence MethodDefSig), now we need to look at some methods from their usage or call sites. In order to illustrate the interesting ones, I'll give an example of a generic calls and the varargs method call (a method that uses the __arglist keyword)
Note: I found an interesting blog entry on the __arglist and other hidden keywords in C# on Bart de Smet's blog: Calling printf from C# - The tale of the hidden __arglist keyword
Example 35: Decoding a call site signature for a Generic method
I've tried to keep the code trimmed down to only the relevant code for the call site.
C# code:
tc.methodGeneric0ParamVoidRet<string>();
IL Dasm:
First the IL Bytes:
The disassembled translation of the bytes:
6F is the IL Instruction callvirt - which takes a method metadata token (which may be a methoddef, methodref or a methodspec) - in the above case you can see the token starts with 2B - so it is a MethodSpec. If you look at the MethodSpec table and the record with index of 1 you will see the detail on the method:
The first column indicates the instantiated method, which is in the Method table, record # 4:
The second column points to the blob heap where the MethodSpec instantiation signature resides:
Blob Heap entry:
Method Spec entry detail:
The syntax of a MethodSpec signature is (from Partition II, page 161):
MethodSpecBlob ::= GENRICINST GenArgCount Type Type*
GENRICINST has the value 0x0A. [Note: This value is known as IMAGE_CEE_CS_CALLCONV_GENERICINST in the Microsoft CLR implementation. end note] The GenArgCount is a compressed int32 indicating the number of generic arguments in the method. The blob then specifies the instantiated type, repeating a total of GenArgCount times.
So the signature is:
0x0a = GENRICINST
0x01 = 1 generic argument
0x0e = ELEMENT_TYPE_STRING
All this put together means: the callvirt instruction is for the method methodGeneric0ParamVoidRet, which is being instantiated with a string type.
Example 36: Decoding a call site signature for a Varargs method
C# Code:
tc.VariableArguments(__arglist(1, 2, 3));
ILDasm:
IL Bytes:
The disassembled translation of the bytes:
The same as above, 6F is the IL instruction for callvirt, which takes a method metadatatoken as a parameter. In this case the token starts with 0A - so it is a record from the MemberRef table (which since it is a method, I'll call it a MethedRef).
Looking at the MethodRefSig syntax diagram at the top of this entry, we can decode the signature as:
0x25 = IMAGE_CEE_CS_CALLCONV_HASTHIS (0x20) and IMAGE_CEE_CS_CALLCONV_VARARG (0x05)
0x03 = Parameter Count - number of parameters at the calling site
0x01 = return type of void (ELEMENT_TYPE_VOID - 0x01)
0x41 = SENTINEL - used to encode "..."
0x08 - type of parameter 1 (ELEMENT_TYPE_I4 - int32)
0x08 - type of parameter 2 (ELEMENT_TYPE_I4 - int32)
0x08 - type of parameter 3 (ELEMENT_TYPE_I4 - int32)
Put all this together and you get an instance method that has varargs, but in this case has 3 int arguments passed to it and returns a void.
Next notes topic will be:
- Property Signatures