-
Notifications
You must be signed in to change notification settings - Fork 223
AssemblyHeader
#####(CLR_RECORD_ASSEMBLY) The AssemblyHeader structure contains a number of verification markers and CRCs to validate the legitimacy of the assembly at runtime. Additionally, the Assembly header contains the location information for the MetadataTables and BLOB storage areas.
The Structure of the AssemblyHeader is as follows:
Name | Type | Description |
---|---|---|
Marker | uint8_t[8] |
Id marker for an assembly |
HeaderCRC | uint32_t |
CRC32 of the AssemblyHeader structure itself |
AssemblyCRC | uint32_t |
CRC32 of the complete assembly |
Flags | AssemblyHeaderFlags | Flags for the assembly |
NativeMethodsChecksum | uint32_t |
Native Method Checksum |
PatchEntryOffset | uint32_t |
Offset into ResourceData table of patch native method |
Version | VersionInfo |
Version information data structure for this assembly |
AssemblyName | uint16_t |
String table index for the Assembly's name |
StartOfTables | uint32_t[16] |
Array of offsets into the PE file for the metadata tables |
NumPatchedMethods | uint32_t |
(Deprecated) No longer used |
PaddingOfTables | uint8_t[16] |
amount of alignment padding for each metadata table |
The following sections describe the individual fields of the AssemblyHeader structure.
The assembly marker is an eight character marker consisting of a string non zero terminated ASCII encoded characters. This is used to clearly identify a .NET Micro Framework PE file on disk and in memory at runtime. It also indicates the version of this data structure, thus any modifications to this structure in future releases MUST use a new marker string. For All released versions of NETMF up to and including v4.4 this string is 'MSSpot1'
ANSI X3.66 32 bit CRC for the AssemblyHeader. This is computed assuming the HeaderCRC and AssemblyCRC fields are 0.
ANSI X3.66 32 bit CRC for the entire contents of the Assembly PE data. This is computed assuming the HeaderCRC and AssemblyCRC fields are 0.
The flags property contains a bit flags value indicating core information about the assembly the possible flags are:
Name | value | Description |
---|---|---|
None | 0x00000000 | No special flags |
NeedReboot | 0x00000001 | Indicates the CLR must be rebooted before this assembly can be loaded |
Patch | 0x00000002 | (Deprecated) Indicates the assembly is a patch assembly |
BigEndian | 0x80000080 | Flag to indicate the assembly is in big-endian format |
NeedReboot has dubious value and should be considered deprecated. It indicates to the CLR that the system must be rebooted before the assembly can be loaded. Presumably the reboot process would either clear the flag or replace the assembly as it would otherwise not be able to load the assembly after the reboot.
The Patch flag is not currently used (Technically it is used but the remaining code that does use it is effectively a NOP) and should be considered deprecated.
The BigEndian flag indicates if the assembly is stored in big-endian mode. This value was deliberately chosen such that it reads the same from both little-endian and big-endian readers. Thus any reader reading the assembly can easily determine the endianess of the assembly data. This should also apply to all of the data stored in the Resources for the assembly. NETMF tools explicitly define and use two types of binary data structures (Bitmaps and fonts) so the tools automatically handle converting the binary data of those structures. Any custom binary resources must account for the endianess conversions either at build time or at runtime in the code that uses the resources.
The NativeMethodsChecksum is a unique value that is matched against the native methods table stored in the CLR firmware to ensure the methods match. The actual algorithm used for computing this checksum are documented in the [NativeMethodsChecksum Algorithm] document. Though, it worth noting that the actual algorithm doesn't matter. Nothing in the runtime will compute this value. The runtime only compares the assembly's value with the one for the native code registered for a given assembly to ensure they match. As long as the tool generating the assembly and the native method stubs header and code files use the same value then the actual algorithm is mostly irrelevant. The most important aspect of the algorithm chosen is that any change to any type or method signature of any type with native methods MUST generate a distinct checksum value. The current MetadataProcessor algorithm constructs a mangled string name for the native methods (used to generate the stubs), sorts them all and runs a CRC32 across them to get a distinct value. Since the CRC is based on the fully qualified method name and the types of all parameters any change of the signatures will generate a new value - denoting a mismatch.
The PatchEntryOffset field is an offset into the assemblies ResourceData blob table where native "patch" code exists. At runtime
if this is not 0xFFFFFFFF then the CLR will compute a physical address of the start of the patch code and call the function located
there. The function must be position independent and must have the following signature void PatchEntry()
This is a very limited
mechanism at present and ultimately requires deep knowledge of the underlying platform HAL/PAL etc... to be of any real use. Of
special importance is the location of the assembly in physical memory as many micro controllers limit the memory addresses where
executable code can reside. (i.e. internal flash or RAM only ) thus, this is not a generalized extensibility/dynamically loaded
native code mechanism.
The Version field holds the assembly's version number. (as opposed to the version of the AssemblyHeaderStructure itself). This is used by the debugger for version checks at deployment time. The runtime itself doesn't use versions to resolve references, as only one version of an assembly can be loaded at a time. Thus assembly references in the PE format don't include a version.
String Table index for the name of the assembly
Fixed array of offsets to the table data for each of the 16 different tables. The entries in this array are offsets from the start of the assembly header itself (e.g. the file seek offset if the PE image is from a file)
Name | NETMF Source Element Name | Description |
---|---|---|
AssemblyRef | CLR_RECORD_ASSEMBLYREF | Table of Assembly references |
TypeRef | CLR_RECORD_TYPEREF | Reference to a type in another assembly |
FieldRef | CLR_RECORD_FIELDREF | Reference to a field of a type in another assembly |
MethodRef | CLR_RECORD_METHODREF | Reference to a method of a type in another assembly |
TypeDef | CLR_RECORD_TYPEDEF | Type definition for a type in this assembly |
FieldDef | CLR_RECORD_FIELDDEF | Field definition for a type in this assembly |
MethodDef | CLR_RECORD_METHODDEF | Method definition for a type in this assembly |
Attributes | CLR_RECORD_ATTRIBUTE | Attribute types defined in this assembly |
TypeSpec | CLR_RECORD_TYPESPEC | TypeSpecifications (signatures) used in this assembly |
Resources | CLR_RECORD_RESOURCE | Resource items in a resource file bound to this assembly |
ResourcesData | <blob> | Blob table data for the resources |
Strings | <blob> | Blob table data for the strings |
Signatures | <blob> | Blob table data for the metadata signatures |
ByteCode | <blob> | Blob table data for the IL byte code instructions |
ResourcesFiles | CLR_RECORD_RESOURCE_FILE | Resource files descriptors for resource files bound to this assembly |
EndOfAssembly | <N/A> | Technically, this is not a table. Instead this entry contains the offset to the end of the assembly, which is useful for finding the next assembly in a DAT region |
For every table, a number of bytes that were padded to the end of the table to align the next table to a
32bit boundary. The start of each table is aligned to a 32bit boundary, and ends at a 32bit boundary.
Some of these tables will, therefore, have no padding, and all will have values in the range [0-3]. This
isn't the most compact form to hold this information, but it only costs 16 bytes/assembly. Trying to only
align some of the tables is just much more hassle than it's worth. This field itself must also be aligned
on a 32 bit boundary. This padding is used to compute the size of a given table (including the blob data)
using the following formula:
TableSize = StartOfTables[ tableindex + 1 ] - StartOfTables[ tableindex ] - PaddingOfTables[ tableindex ]