Introduction
A signature is a #Blob entry that describes a type, a field, a method, a property, the locals of a method or the type arguments of a generic method call. Types are written
as a sequence of element type bytes with compressed integers for counts and indexes. A type named by a token uses a TypeDefOrRef coded index, compressed.
The kinds of signature
The first byte is a header: its low four bits give the kind, the high bits flags (0x10 generic, 0x20 has this, 0x40 explicit this).
| Low bits | Kind | Layout | Used by |
|---|---|---|---|
| 0 to 5, 9 | Method | header; if generic, the number of generic parameters; the parameter count; the return type; the parameters. A 0x41 before a parameter starts the optional (vararg) parameters. Calling conventions: 0 default, 1 C, 2 stdcall, 3 thiscall, 4 fastcall, 5 vararg, 9 unmanaged. | MethodDef, MemberRef, StandAloneSig (calli), function pointer types |
| 6 | Field | header, then one type. | Field, MemberRef |
| 7 | Local variables | header, the count (at least 1), then each local’s type; a local may be marked pinned and may be by-reference. | StandAloneSig |
| 8 | Property | as a method signature: the return type is the property type, the parameters are the index parameters. | Property |
| 10 | Method instantiation | header, the number of type arguments, the types. | MethodSpec |
A TypeSpec blob is not a signature in this sense: it is one bare type with no header byte.
Types
| Byte | Name | Followed by |
|---|---|---|
| 0x01 to 0x0E | VOID, BOOLEAN, CHAR, I1, U1, I2, U2, I4, U4, I8, U8, R4, R8, STRING | nothing |
| 0x0F | PTR | a type (custom modifiers may come first) |
| 0x10 | BYREF | a type |
| 0x11, 0x12 | VALUETYPE, CLASS | a TypeDefOrRef coded index |
| 0x13, 0x1E | VAR, MVAR | the number of a generic parameter of the type, or of the method |
| 0x14 | ARRAY | the element type; the rank; the number of sizes and the sizes; the number of lower bounds and the (signed) bounds |
| 0x15 | GENERICINST | CLASS or VALUETYPE and its token; the number of arguments; the argument types |
| 0x16 | TYPEDBYREF | nothing |
| 0x18, 0x19 | I, U (native integers) | nothing |
| 0x1B | FNPTR | a method signature |
| 0x1C | OBJECT | nothing |
| 0x1D | SZARRAY | the element type (a single-dimension array with lower bound 0) |
| 0x1F, 0x20 | CMOD_REQD, CMOD_OPT | a TypeDefOrRef coded index, then the type it modifies: a required or optional custom modifier (IsVolatile on a volatile field, InAttribute on a read-only reference parameter) |
| 0x41 | SENTINEL | in a method signature, before the first vararg parameter |
| 0x45 | PINNED | a type (a pinned local) |
How the explorer prints them
In a table row a signature is shown as the types it holds; in the Types listing it becomes a C# declaration: primitives by their C# keyword, a generic instantiation as List<string>
(the backtick arity of the name removed), arrays as T[] and T[,], pointers and function pointers as in C#, by-reference parameters as ref, out or in by the parameter flags,
generic parameters by the names of the GenericParam table, custom modifiers as comments. Nullable<T> prints as T?. A malformed signature is reported with where it went wrong and the declaration says it is unreadable.
Not described
Known, not yet covered
- Viewer: the element types used only inside custom attribute values (0x50 TYPE, 0x51 BOXED, 0x55 ENUM) belong to the attribute encoding, which is not decoded yet; the INTERNAL element type (0x21) is not accepted and is reported as a malformed signature.
- Viewer: a local signature with no locals is refused, as the specification requires at least one; real compilers of the early 2000s wrote them and Microsoft’s own reader refuses them too.
Links
Reference
- ECMA-335 – partition II section 23.2: blobs and signatures