// Copyright © Microsoft Corporation. // This source file is subject to the Microsoft Permissive License. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. // All other rights reserved. using System; #if FxCop using Win32ResourceList = Microsoft.Cci.Win32ResourceCollection; using TypeNodeList = Microsoft.Cci.TypeNodeCollection; #endif #if CCINamespace using Microsoft.Cci; #else using System.Compiler; #endif using System.Collections; using System.Diagnostics; using System.Globalization; using System.Runtime.Serialization; //^ using Microsoft.Contracts; /* These classes help with parsing and producing PE files. They are best understood in conjunction with the ECMA 335 Specification * (Common Language Infrastructure), particularly Partition II. Also see "Inside Microsoft .NET IL Assembler" by Serge Lidin. */ #if CCINamespace namespace Microsoft.Cci.Metadata{ #else namespace System.Compiler.Metadata { #endif internal struct AssemblyRow { internal int HashAlgId; internal int MajorVersion; internal int MinorVersion; internal int BuildNumber; internal int RevisionNumber; internal int Flags; internal int PublicKey; internal int Name; internal int Culture; } internal struct AssemblyRefRow { internal int MajorVersion; internal int MinorVersion; internal int BuildNumber; internal int RevisionNumber; internal int Flags; internal int PublicKeyOrToken; internal int Name; internal int Culture; internal int HashValue; internal AssemblyReference AssemblyReference; } internal struct ClassLayoutRow { internal int PackingSize; internal int ClassSize; internal int Parent; } internal struct ConstantRow { internal int Type; internal int Parent; internal int Value; } internal struct CustomAttributeRow { internal int Parent; internal int Constructor; internal int Value; } internal struct DeclSecurityRow { internal int Action; internal int Parent; internal int PermissionSet; } internal struct EventMapRow { internal int Parent; internal int EventList; } internal struct EventPtrRow { internal int Event; } internal struct EventRow { internal int Flags; internal int Name; internal int EventType; } internal struct ExportedTypeRow { internal int Flags; internal int TypeDefId; internal int TypeName; internal int TypeNamespace; internal int Implementation; } internal struct FieldRow { internal int Flags; internal int Name; internal int Signature; internal Field Field; } internal struct FieldLayoutRow { internal int Offset; internal int Field; } internal struct FieldMarshalRow { internal int Parent; internal int NativeType; } internal struct FieldPtrRow { internal int Field; } internal struct FieldRvaRow { internal int RVA; internal int Field; internal PESection TargetSection; } internal struct FileRow { internal int Flags; internal int Name; internal int HashValue; } internal struct GenericParamRow { internal int Number; internal int Flags; internal int Owner; internal int Name; internal Member GenericParameter; } internal struct GenericParamConstraintRow { internal int Param; internal int Constraint; } internal struct ImplMapRow { internal int MappingFlags; internal int MemberForwarded; internal int ImportName; internal int ImportScope; } internal struct InterfaceImplRow { internal int Class; internal int Interface; } internal struct ManifestResourceRow { internal int Offset; internal int Flags; internal int Name; internal int Implementation; } internal struct MemberRefRow { internal int Class; internal int Name; internal int Signature; internal Member Member; internal TypeNodeList VarargTypes; } internal struct MethodRow { internal int RVA; internal int ImplFlags; internal int Flags; internal int Name; internal int Signature; internal int ParamList; internal Method Method; } internal struct MethodImplRow { internal int Class; internal int MethodBody; internal int MethodDeclaration; } internal struct MethodPtrRow { internal int Method; } internal struct MethodSemanticsRow { internal int Semantics; internal int Method; internal int Association; } internal struct MethodSpecRow { internal int Method; internal int Instantiation; internal Method InstantiatedMethod; } internal struct ModuleRow { internal int Generation; internal int Name; internal int Mvid; internal int EncId; internal int EncBaseId; } internal struct ModuleRefRow { internal int Name; #if FxCop internal ModuleNode Module; #else internal Module Module; #endif } internal struct NestedClassRow { internal int NestedClass; internal int EnclosingClass; } internal struct ParamRow { internal int Flags; internal int Sequence; internal int Name; } internal struct ParamPtrRow { internal int Param; } internal struct PropertyRow { internal int Flags; internal int Name; internal int Signature; } internal struct PropertyPtrRow { internal int Property; } internal struct PropertyMapRow { internal int Parent; internal int PropertyList; } internal struct StandAloneSigRow { internal int Signature; } internal struct TypeDefRow { internal int Flags; internal int Name; internal int Namespace; internal int Extends; internal int FieldList; internal int MethodList; internal TypeNode Type; internal Identifier NamespaceId; internal int NamespaceKey; internal int NameKey; } internal struct TypeRefRow { internal int ResolutionScope; internal int Name; internal int Namespace; internal TypeNode Type; } internal struct TypeSpecRow { internal int Signature; internal TypeNode Type; } [Serializable] public sealed class InvalidMetadataException : System.Exception { public InvalidMetadataException() { } public InvalidMetadataException(string message) : base(message) { } public InvalidMetadataException(string message, Exception innerException) : base(message, innerException) { } private InvalidMetadataException(SerializationInfo info, StreamingContext context) : base(info, context) { } } internal class CLIHeader { internal int cb; internal ushort majorRuntimeVersion; internal ushort minorRuntimeVersion; internal DirectoryEntry metaData; internal int flags; internal int entryPointToken; internal DirectoryEntry resources; internal DirectoryEntry strongNameSignature; internal DirectoryEntry codeManagerTable; internal DirectoryEntry vtableFixups; internal DirectoryEntry exportAddressTableJumps; internal CLIHeader() { this.cb = 72; this.majorRuntimeVersion = 2; this.minorRuntimeVersion = 5; // initialization provided by runtime //this.flags = 0; //this.entryPointToken = 0; } } internal struct DirectoryEntry { internal int virtualAddress; internal int size; } internal class MetadataHeader { internal int signature; internal ushort majorVersion; internal ushort minorVersion; internal int reserved; internal string versionString; internal int flags; internal StreamHeader[] streamHeaders; } internal class NTHeader { internal int signature; internal ushort machine; internal ushort numberOfSections; internal int timeDateStamp; internal int pointerToSymbolTable; internal int numberOfSymbols; internal ushort sizeOfOptionalHeader; internal ushort characteristics; internal ushort magic; internal byte majorLinkerVersion; internal byte minorLinkerVersion; internal int sizeOfCode; internal int sizeOfInitializedData; internal int sizeOfUninitializedData; internal int addressOfEntryPoint; internal int baseOfCode; internal int baseOfData; internal long imageBase; internal int sectionAlignment; internal int fileAlignment; internal ushort majorOperatingSystemVersion; internal ushort minorOperatingSystemVersion; internal ushort majorImageVersion; internal ushort minorImageVersion; internal ushort majorSubsystemVersion; internal ushort minorSubsystemVersion; internal int win32VersionValue; internal int sizeOfImage; internal int sizeOfHeaders; internal int checkSum; internal ushort subsystem; internal ushort dllCharacteristics; internal long sizeOfStackReserve; internal long sizeOfStackCommit; internal long sizeOfHeapReserve; internal long sizeOfHeapCommit; internal int loaderFlags; internal int numberOfDataDirectories; internal DirectoryEntry exportTable; internal DirectoryEntry importTable; internal DirectoryEntry resourceTable; internal DirectoryEntry exceptionTable; internal DirectoryEntry certificateTable; internal DirectoryEntry baseRelocationTable; internal DirectoryEntry debugTable; internal DirectoryEntry copyrightTable; internal DirectoryEntry globalPointerTable; internal DirectoryEntry threadLocalStorageTable; internal DirectoryEntry loadConfigTable; internal DirectoryEntry boundImportTable; internal DirectoryEntry importAddressTable; internal DirectoryEntry delayImportTable; internal DirectoryEntry cliHeaderTable; internal DirectoryEntry reserved; internal NTHeader() { this.signature = 0x00004550; /* "PE\0\0" */ this.machine = 0x14c; this.sizeOfOptionalHeader = 224; this.characteristics = 0x0002 | 0x0004 | 0x008 | 0x0100; this.magic = 0x10B; this.majorLinkerVersion = 6; this.baseOfCode = 0x2000; this.imageBase = 0x400000; //TODO: make this settable this.sectionAlignment = 8192; this.fileAlignment = 512; this.majorOperatingSystemVersion = 4; this.majorSubsystemVersion = 4; this.dllCharacteristics = 0x400; this.sizeOfStackReserve = 1048576; this.sizeOfStackCommit = 4096; this.sizeOfHeapReserve = 1048576; this.sizeOfHeapCommit = 4096; this.numberOfDataDirectories = 16; // initialization provided by runtime //this.numberOfSections = 0; //this.timeDateStamp = 0; //this.pointerToSymbolTable = 0; //this.numberOfSymbols = 0; //this.minorLinkerVersion = 0; //this.sizeOfCode = 0; //this.sizeOfInitializedData = 0; //this.sizeOfUninitializedData = 0; //this.addressOfEntryPoint = 0; //this.baseOfData = 0; //this.minorOperatingSystemVersion = 0; //this.majorImageVersion = 0; //this.minorImageVersion = 0; //this.minorSubsystemVersion = 0; //this.win32VersionValue = 0; //this.sizeOfImage = 0; //this.sizeOfHeaders = 0; //this.checkSum = 0; //this.subsystem = 0; //this.loaderFlags = 0x0; } } internal struct SectionHeader { internal string name; internal int virtualSize; internal int virtualAddress; internal int sizeOfRawData; internal int pointerToRawData; internal int pointerToRelocations; internal int pointerToLinenumbers; internal ushort numberOfRelocations; internal ushort numberOfLinenumbers; internal int characteristics; } internal class StreamHeader { internal int offset; internal int size; internal String name; } internal class TablesHeader { internal int reserved; internal byte majorVersion; internal byte minorVersion; internal byte heapSizes; internal byte rowId; internal long maskValid; internal long maskSorted; internal int[] countArray; } internal enum TableIndices { Module = 0x00, TypeRef = 0x01, TypeDef = 0x02, FieldPtr = 0x03, Field = 0x04, MethodPtr = 0x05, Method = 0x06, ParamPtr = 0x07, Param = 0x08, InterfaceImpl = 0x09, MemberRef = 0x0A, Constant = 0x0B, CustomAttribute = 0x0C, FieldMarshal = 0x0D, DeclSecurity = 0x0E, ClassLayout = 0x0F, FieldLayout = 0x10, StandAloneSig = 0x11, EventMap = 0x12, EventPtr = 0x13, Event = 0x14, PropertyMap = 0x15, PropertyPtr = 0x16, Property = 0x17, MethodSemantics = 0x18, MethodImpl = 0x19, ModuleRef = 0x1A, TypeSpec = 0x1B, ImplMap = 0x1C, FieldRva = 0x1D, EncLog = 0x1E, EncMap = 0x1F, Assembly = 0x20, AssemblyProcessor = 0x21, AssemblyOS = 0x22, AssemblyRef = 0x23, AssemblyRefProcessor = 0x24, AssemblyRefOS = 0x25, File = 0x26, ExportedType = 0x27, ManifestResource = 0x28, NestedClass = 0x29, GenericParam = 0x2a, MethodSpec = 0x2b, GenericParamConstraint = 0x2c, Count } internal enum ElementType { End = 0x00, Void = 0x01, Boolean = 0x02, Char = 0x03, Int8 = 0x04, UInt8 = 0x05, Int16 = 0x06, UInt16 = 0x07, Int32 = 0x08, UInt32 = 0x09, Int64 = 0x0a, UInt64 = 0x0b, Single = 0x0c, Double = 0x0d, String = 0x0e, Pointer = 0x0f, Reference = 0x10, ValueType = 0x11, Class = 0x12, TypeParameter = 0x13, Array = 0x14, GenericTypeInstance = 0x15, DynamicallyTypedReference = 0x16, IntPtr = 0x18, UIntPtr = 0x19, FunctionPointer = 0x1b, Object = 0x1c, SzArray = 0x1d, MethodParameter = 0x1e, RequiredModifier = 0x1f, OptionalModifier = 0x20, Internal = 0x21, Modifier = 0x40, Sentinel = 0x41, Pinned = 0x45, Type = 0x50, BoxedEnum = 0x51, Enum = 0x55 } unsafe internal class MetadataReader : IDisposable { #if !ROTOR private MemoryMappedFile memmap; #endif private MemoryCursor/*!*/ cursor; internal int entryPointToken; internal int fileAlignment; internal ModuleKindFlags moduleKind; internal PEKindFlags peKind; internal bool TrackDebugData; private int mdOffset; private int resourcesOffset; private int win32ResourcesOffset; private SectionHeader[] sectionHeaders; //^ [SpecPublic] private StreamHeader identifierStringHeap; //^ [SpecPublic] private StreamHeader generalStringHeap; private StreamHeader blobHeap; //^ [SpecPublic] private StreamHeader guidHeap; private StreamHeader tables; internal TablesHeader tablesHeader; internal string targetRuntimeVersion; internal int linkerMajorVersion; internal int linkerMinorVersion; internal int metadataFormatMajorVersion; internal int metadataFormatMinorVersion; private int blobRefSize; private int constantParentRefSize; private int customAttributeParentRefSize; private int customAttributeConstructorRefSize; private int declSecurityParentRefSize; private int fieldMarshalParentRefSize; private int guidRefSize; private int hasSemanticRefSize; private int implementationRefSize; private int methodDefOrRefSize; private int memberRefParentSize; private int memberForwardedRefSize; private int typeDefOrRefOrSpecSize; private int typeDefOrMethodDefSize; private int resolutionScopeRefSize; private int stringRefSize; private int[] tableSize; private int[] tableRefSize; private int[] tableOffset; internal byte[] HashValue; #if !ROTOR internal MetadataReader(string path) { MemoryMappedFile memmap = this.memmap = new MemoryMappedFile(path); try { this.cursor = new MemoryCursor(memmap); //^ base(); ReadHeader(); } catch { this.Dispose(); throw; } } #endif internal MetadataReader(byte* buffer, int length) { this.cursor = new MemoryCursor(buffer, length); //^ base(); ReadHeader(); } public void Dispose() { #if !ROTOR if (this.memmap != null) this.memmap.Dispose(); this.memmap = null; #endif //this.cursor = null; this.sectionHeaders = null; this.identifierStringHeap = null; this.generalStringHeap = null; this.blobHeap = null; this.guidHeap = null; this.tables = null; this.tablesHeader = null; this.targetRuntimeVersion = null; this.tableSize = null; this.tableRefSize = null; this.tableOffset = null; this.HashValue = null; } private AssemblyRow[] assemblyTable; private AssemblyRefRow[] assemblyRefTable; private ClassLayoutRow[] classLayoutTable; private ConstantRow[] constantTable; private CustomAttributeRow[] customAttributeTable; private DeclSecurityRow[] declSecurityTable; private EventMapRow[] eventMapTable; private EventPtrRow[] eventPtrTable; private EventRow[] eventTable; private ExportedTypeRow[] exportedTypeTable; private FieldRow[] fieldTable; private FieldLayoutRow[] fieldLayoutTable; private FieldMarshalRow[] fieldMarshalTable; private FieldPtrRow[] fieldPtrTable; private FieldRvaRow[] fieldRvaTable; private FileRow[] fileTable; private GenericParamRow[] genericParamTable; private GenericParamConstraintRow[] genericParamConstraintTable; private ImplMapRow[] implMapTable; private InterfaceImplRow[] interfaceImplTable; private ManifestResourceRow[] manifestResourceTable; private MemberRefRow[] memberRefTable; private MethodRow[] methodTable; private MethodPtrRow[] methodPtrTable; private MethodImplRow[] methodImplTable; private MethodSemanticsRow[] methodSemanticsTable; private MethodSpecRow[] methodSpecTable; private ModuleRow[] moduleTable; private ModuleRefRow[] moduleRefTable; private NestedClassRow[] nestedClassTable; private ParamRow[] paramTable; private ParamPtrRow[] paramPtrTable; private PropertyRow[] propertyTable; private PropertyMapRow[] propertyMapTable; private PropertyPtrRow[] propertyPtrTable; private StandAloneSigRow[] standAloneSigTable; private TypeDefRow[] typeDefTable; private TypeRefRow[] typeRefTable; private TypeSpecRow[] typeSpecTable; internal AssemblyRow[]/*!*/ AssemblyTable { get { if (this.assemblyTable == null) this.ReadAssemblyTable(); return this.assemblyTable; } } internal AssemblyRefRow[]/*!*/ AssemblyRefTable { get { if (this.assemblyRefTable == null) this.ReadAssemblyRefTable(); return this.assemblyRefTable; } } internal ClassLayoutRow[]/*!*/ ClassLayoutTable { get { if (this.classLayoutTable == null) this.ReadClassLayoutTable(); return this.classLayoutTable; } } internal ConstantRow[]/*!*/ ConstantTable { get { if (this.constantTable == null) this.ReadConstantTable(); return this.constantTable; } } internal CustomAttributeRow[]/*!*/ CustomAttributeTable { get { if (this.customAttributeTable == null) this.ReadCustomAttributeTable(); return this.customAttributeTable; } } internal DeclSecurityRow[]/*!*/ DeclSecurityTable { get { if (this.declSecurityTable == null) this.ReadDeclSecurityTable(); return this.declSecurityTable; } } internal EventMapRow[]/*!*/ EventMapTable { get { if (this.eventMapTable == null) this.ReadEventMapTable(); return this.eventMapTable; } } internal EventPtrRow[]/*!*/ EventPtrTable { get { if (this.eventPtrTable == null) this.ReadEventPtrTable(); return this.eventPtrTable; } } internal EventRow[]/*!*/ EventTable { get { if (this.eventTable == null) this.ReadEventTable(); return this.eventTable; } } internal ExportedTypeRow[]/*!*/ ExportedTypeTable { get { if (this.exportedTypeTable == null) this.ReadExportedTypeTable(); return this.exportedTypeTable; } } internal FieldRow[]/*!*/ FieldTable { get { if (this.fieldTable == null) this.ReadFieldTable(); return this.fieldTable; } } internal FieldLayoutRow[]/*!*/ FieldLayoutTable { get { if (this.fieldLayoutTable == null) this.ReadFieldLayoutTable(); return this.fieldLayoutTable; } } internal FieldMarshalRow[]/*!*/ FieldMarshalTable { get { if (this.fieldMarshalTable == null) this.ReadFieldMarshalTable(); return this.fieldMarshalTable; } } internal FieldPtrRow[]/*!*/ FieldPtrTable { get { if (this.fieldPtrTable == null) this.ReadFieldPtrTable(); return this.fieldPtrTable; } } internal FieldRvaRow[]/*!*/ FieldRvaTable { get { if (this.fieldRvaTable == null) this.ReadFieldRvaTable(); return this.fieldRvaTable; } } internal FileRow[]/*!*/ FileTable { get { if (this.fileTable == null) this.ReadFileTable(); return this.fileTable; } } internal GenericParamRow[]/*!*/ GenericParamTable { get { if (this.genericParamTable == null) this.ReadGenericParamTable(); return this.genericParamTable; } } internal GenericParamConstraintRow[]/*!*/ GenericParamConstraintTable { get { if (this.genericParamConstraintTable == null) this.ReadGenericParamConstraintTable(); return this.genericParamConstraintTable; } } internal ImplMapRow[]/*!*/ ImplMapTable { get { if (this.implMapTable == null) this.ReadImplMapTable(); return this.implMapTable; } } internal InterfaceImplRow[]/*!*/ InterfaceImplTable { get { if (this.interfaceImplTable == null) this.ReadInterfaceImplTable(); return this.interfaceImplTable; } } internal ManifestResourceRow[]/*!*/ ManifestResourceTable { get { if (this.manifestResourceTable == null) this.ReadManifestResourceTable(); return this.manifestResourceTable; } } internal MemberRefRow[]/*!*/ MemberRefTable { get { if (this.memberRefTable == null) this.ReadMemberRefTable(); return this.memberRefTable; } } internal MethodRow[]/*!*/ MethodTable { get { if (this.methodTable == null) this.ReadMethodTable(); return this.methodTable; } } internal MethodImplRow[]/*!*/ MethodImplTable { get { if (this.methodImplTable == null) this.ReadMethodImplTable(); return this.methodImplTable; } } internal MethodPtrRow[]/*!*/ MethodPtrTable { get { if (this.methodPtrTable == null) this.ReadMethodPtrTable(); return this.methodPtrTable; } } internal MethodSemanticsRow[]/*!*/ MethodSemanticsTable { get { if (this.methodSemanticsTable == null) this.ReadMethodSemanticsTable(); return this.methodSemanticsTable; } } internal MethodSpecRow[]/*!*/ MethodSpecTable { get { if (this.methodSpecTable == null) this.ReadMethodSpecTable(); return this.methodSpecTable; } } internal ModuleRow[]/*!*/ ModuleTable { get { if (this.moduleTable == null) this.ReadModuleTable(); return this.moduleTable; } } internal ModuleRefRow[]/*!*/ ModuleRefTable { get { if (this.moduleRefTable == null) this.ReadModuleRefTable(); return this.moduleRefTable; } } internal NestedClassRow[]/*!*/ NestedClassTable { get { if (this.nestedClassTable == null) this.ReadNestedClassTable(); return this.nestedClassTable; } } internal ParamRow[]/*!*/ ParamTable { get { if (this.paramTable == null) this.ReadParamTable(); return this.paramTable; } } internal ParamPtrRow[]/*!*/ ParamPtrTable { get { if (this.paramPtrTable == null) this.ReadParamPtrTable(); return this.paramPtrTable; } } internal PropertyRow[]/*!*/ PropertyTable { get { if (this.propertyTable == null) this.ReadPropertyTable(); return this.propertyTable; } } internal PropertyMapRow[]/*!*/ PropertyMapTable { get { if (this.propertyMapTable == null) this.ReadPropertyMapTable(); return this.propertyMapTable; } } internal PropertyPtrRow[]/*!*/ PropertyPtrTable { get { if (this.propertyPtrTable == null) this.ReadPropertyPtrTable(); return this.propertyPtrTable; } } internal StandAloneSigRow[]/*!*/ StandAloneSigTable { get { if (this.standAloneSigTable == null) this.ReadStandAloneSigTable(); return this.standAloneSigTable; } } internal TypeDefRow[]/*!*/ TypeDefTable { get { if (this.typeDefTable == null) this.ReadTypeDefTable(); return this.typeDefTable; } } internal TypeRefRow[]/*!*/ TypeRefTable { get { if (this.typeRefTable == null) this.ReadTypeRefTable(); return this.typeRefTable; } } internal TypeSpecRow[]/*!*/ TypeSpecTable { get { if (this.typeSpecTable == null) this.ReadTypeSpecTable(); return this.typeSpecTable; } } internal void SetCurrentPosition(int pos) { this.cursor.Position = pos; } internal void AlignTo32BitBoundary() { this.cursor.Align(4); } internal void Skip(int bytes) { this.cursor.SkipByte(bytes); } internal byte[]/*!*/ GetBlob(int blobIndex) { MemoryCursor c = this.cursor; c.Position = PositionOfBlob(blobIndex); return c.ReadBytes(c.ReadCompressedInt()); } internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex) { MemoryCursor c = this.cursor; c.Position = PositionOfBlob(blobIndex); c.ReadCompressedInt(); return new MemoryCursor(c); } internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex, out int blobLength) { MemoryCursor c = this.cursor; c.Position = PositionOfBlob(blobIndex); blobLength = c.ReadCompressedInt(); return new MemoryCursor(c); } internal System.Guid GetGuid(int guidIndex) //^ requires this.guidHeap != null; { int guidOffset = guidIndex * 16; if (guidOffset < 16 || this.guidHeap.size < guidOffset) throw new System.ArgumentOutOfRangeException("guidIndex", ExceptionStrings.BadGuidHeapIndex); MemoryCursor c = this.cursor; c.Position = this.mdOffset + this.guidHeap.offset + guidOffset - 16; return new System.Guid(c.ReadBytes(16)); } internal Identifier/*!*/ GetIdentifier(int stringHeapIndex) //^ requires this.identifierStringHeap != null; { int position = this.mdOffset + this.identifierStringHeap.offset + stringHeapIndex; MemoryCursor c = this.cursor; return Identifier.For(c.GetBuffer(), position/*, c.KeepAlive*/); } internal byte GetMethodBodyHeaderByte(int RVA) { MemoryCursor c = this.cursor; c.Position = this.RvaToOffset(RVA); return c.ReadByte(); } internal MemoryCursor/*!*/ GetNewCursor() { return new MemoryCursor(this.cursor); } internal MemoryCursor/*!*/ GetNewCursor(int RVA, out PESection targetSection) { MemoryCursor c = new MemoryCursor(this.cursor); c.Position = this.RvaToOffset(RVA, out targetSection); return c; } internal byte GetByte() { MemoryCursor c = this.cursor; return c.ReadByte(); } internal int GetCurrentPosition() { return this.cursor.Position; } internal int GetInt32() { MemoryCursor c = this.cursor; return c.ReadInt32(); } internal short GetInt16() { MemoryCursor c = this.cursor; return c.ReadInt16(); } internal ushort GetUInt16() { MemoryCursor c = this.cursor; return c.ReadUInt16(); } internal int GetSignatureLength(int blobIndex) { MemoryCursor c = this.cursor; c.Position = this.PositionOfBlob(blobIndex); return c.ReadCompressedInt(); } internal string/*!*/ GetString(int stringHeapIndex) //^ requires this.identifierStringHeap != null; { if (stringHeapIndex < 0 || this.identifierStringHeap.size <= stringHeapIndex) throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadStringHeapIndex); MemoryCursor c = this.cursor; c.Position = this.mdOffset + this.identifierStringHeap.offset + stringHeapIndex; return c.ReadUTF8(); } internal string/*!*/ GetUserString(int stringHeapIndex) //^ requires this.generalStringHeap != null; { if (stringHeapIndex < 0 || this.generalStringHeap.size <= stringHeapIndex) throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadUserStringHeapIndex); MemoryCursor c = this.cursor; c.Position = this.mdOffset + this.generalStringHeap.offset + stringHeapIndex; int strLength = c.ReadCompressedInt(); return c.ReadUTF16(strLength / 2); } internal string/*!*/ GetBlobString(int blobIndex) { MemoryCursor c = this.cursor; c.Position = this.PositionOfBlob(blobIndex); int blobLength = c.ReadCompressedInt(); return c.ReadUTF16(blobLength / 2); } internal object GetValueFromBlob(int type, int blobIndex) { MemoryCursor c = this.cursor; c.Position = this.PositionOfBlob(blobIndex); int blobLength = c.ReadCompressedInt(); switch ((ElementType)type) { case ElementType.Boolean: return c.ReadBoolean(); case ElementType.Char: return (char)c.ReadUInt16(); case ElementType.Double: return c.ReadDouble(); case ElementType.Single: return c.ReadSingle(); case ElementType.Int16: return c.ReadInt16(); case ElementType.Int32: return c.ReadInt32(); case ElementType.Int64: return c.ReadInt64(); case ElementType.Int8: return c.ReadSByte(); case ElementType.UInt16: return c.ReadUInt16(); case ElementType.UInt32: return c.ReadUInt32(); case ElementType.UInt64: return c.ReadUInt64(); case ElementType.UInt8: return c.ReadByte(); case ElementType.Class: return null; case ElementType.String: return c.ReadUTF16(blobLength / 2); } throw new InvalidMetadataException(ExceptionStrings.UnknownConstantType); } internal byte[] GetResourceData(int resourceOffset) { this.cursor.Position = this.resourcesOffset + resourceOffset; int length = this.cursor.ReadInt32(); return this.cursor.ReadBytes(length); } private int PositionOfBlob(int blobIndex) //^ requires this.blobHeap != null; { if (blobIndex < 0 || this.blobHeap.size <= blobIndex) throw new System.ArgumentOutOfRangeException("blobIndex", ExceptionStrings.BadBlobHeapIndex); return this.mdOffset + this.blobHeap.offset + blobIndex; } private void ReadHeader() { //TODO: break up this method MemoryCursor c = this.cursor; c.Position = 0; ReadDOSHeader(c); NTHeader ntHeader = ReadNTHeader(c); this.linkerMajorVersion = ntHeader.majorLinkerVersion; this.linkerMinorVersion = ntHeader.minorLinkerVersion; this.fileAlignment = ntHeader.fileAlignment; if ((ntHeader.characteristics & 0x2000) != 0) this.moduleKind = ModuleKindFlags.DynamicallyLinkedLibrary; else this.moduleKind = ntHeader.subsystem == 0x3 ? ModuleKindFlags.ConsoleApplication : ModuleKindFlags.WindowsApplication; int sectionCount = ntHeader.numberOfSections; SectionHeader[] sectionHeaders = this.sectionHeaders = new SectionHeader[sectionCount]; int resourceSectionIndex = -1; for (int i = 0; i < sectionCount; i++) { sectionHeaders[i] = ReadSectionHeader(c); if (sectionHeaders[i].name == ".rsrc") resourceSectionIndex = i; } if (resourceSectionIndex >= 0) this.win32ResourcesOffset = sectionHeaders[resourceSectionIndex].pointerToRawData; else this.win32ResourcesOffset = -1; DirectoryEntry de = ntHeader.cliHeaderTable; int cliHeaderOffset = this.RvaToOffset(de.virtualAddress); c.Position = cliHeaderOffset; CLIHeader cliHeader = ReadCLIHeader(c); this.entryPointToken = cliHeader.entryPointToken; if ((cliHeader.flags & 1) != 0) this.peKind = PEKindFlags.ILonly; if ((cliHeader.flags & 0x10) != 0) this.entryPointToken = 0; //Native entry point. Ignore. switch (ntHeader.machine) { case 0x0200: this.peKind |= PEKindFlags.Requires64bits; break; case 0x8664: this.peKind |= PEKindFlags.Requires64bits | PEKindFlags.AMD; break; default: if (ntHeader.magic == 0x20B) //Optional header magic for PE32+ this.peKind |= PEKindFlags.Requires64bits; else if ((cliHeader.flags & 2) != 0) this.peKind |= PEKindFlags.Requires32bits; break; } this.TrackDebugData = (cliHeader.flags & 0x10000) != 0; if (cliHeader.resources.size > 0) this.resourcesOffset = this.RvaToOffset(cliHeader.resources.virtualAddress); int snSize = cliHeader.strongNameSignature.size; if (snSize > 0) { long hashOffset = this.RvaToOffset(cliHeader.strongNameSignature.virtualAddress); c.Position = (int)hashOffset; this.HashValue = c.ReadBytes(snSize); bool zeroHash = true; for (int i = 0; i < snSize; i++) if (this.HashValue[i] != 0) zeroHash = false; if (zeroHash) this.HashValue = null; //partially signed assembly } long mdOffset = this.mdOffset = this.RvaToOffset(cliHeader.metaData.virtualAddress); c.Position = (int)mdOffset; MetadataHeader mdHeader = ReadMetadataHeader(c); this.targetRuntimeVersion = mdHeader.versionString; foreach (StreamHeader sheader in mdHeader.streamHeaders) { //^ assume sheader != null; switch (sheader.name) { case "#Strings": this.identifierStringHeap = sheader; continue; case "#US": this.generalStringHeap = sheader; continue; case "#Blob": this.blobHeap = sheader; continue; case "#GUID": this.guidHeap = sheader; continue; case "#~": this.tables = sheader; continue; case "#-": this.tables = sheader; continue; default: continue; } } if (this.tables == null) throw new InvalidMetadataException(ExceptionStrings.NoMetadataStream); c.Position = (int)(mdOffset + this.tables.offset); TablesHeader tablesHeader = this.tablesHeader = ReadTablesHeader(c); this.metadataFormatMajorVersion = tablesHeader.majorVersion; this.metadataFormatMinorVersion = tablesHeader.minorVersion; int[] tableSize = this.tableSize = new int[(int)TableIndices.Count]; int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count]; long valid = tablesHeader.maskValid; int[] countArray = tablesHeader.countArray; //^ assume countArray != null; for (int i = 0, j = 0; i < (int)TableIndices.Count; i++) { if (valid % 2 == 1) { int m = tableSize[i] = countArray[j++]; tableRefSize[i] = m < 0x10000 ? 2 : 4; } else tableRefSize[i] = 2; valid /= 2; } int blobRefSize = this.blobRefSize = ((tablesHeader.heapSizes & 0x04) == 0 ? 2 : 4); int constantParentRefSize = this.constantParentRefSize = tableSize[(int)TableIndices.Param] < 0x4000 && tableSize[(int)TableIndices.Field] < 0x4000 && tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4; int customAttributeParentRefSize = 0; if (this.metadataFormatMajorVersion > 1 || this.metadataFormatMinorVersion > 0) { customAttributeParentRefSize = this.customAttributeParentRefSize = tableSize[(int)TableIndices.Method] < 0x0800 && tableSize[(int)TableIndices.Field] < 0x0800 && tableSize[(int)TableIndices.TypeRef] < 0x0800 && tableSize[(int)TableIndices.TypeDef] < 0x0800 && tableSize[(int)TableIndices.Param] < 0x0800 && tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 && tableSize[(int)TableIndices.MemberRef] < 0x0800 && tableSize[(int)TableIndices.Module] < 0x0800 && tableSize[(int)TableIndices.DeclSecurity] < 0x0800 && tableSize[(int)TableIndices.Property] < 0x0800 && tableSize[(int)TableIndices.Event] < 0x0800 && tableSize[(int)TableIndices.StandAloneSig] < 0x0800 && tableSize[(int)TableIndices.ModuleRef] < 0x0800 && tableSize[(int)TableIndices.TypeSpec] < 0x0800 && tableSize[(int)TableIndices.Assembly] < 0x0800 && tableSize[(int)TableIndices.File] < 0x0800 && tableSize[(int)TableIndices.ExportedType] < 0x0800 && tableSize[(int)TableIndices.ManifestResource] < 0x0800 && tableSize[(int)TableIndices.GenericParam] < 0x0800 && tableSize[(int)TableIndices.MethodSpec] < 0x0800 && tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4; } else { customAttributeParentRefSize = this.customAttributeParentRefSize = tableSize[(int)TableIndices.Method] < 0x0800 && tableSize[(int)TableIndices.Field] < 0x0800 && tableSize[(int)TableIndices.TypeRef] < 0x0800 && tableSize[(int)TableIndices.TypeDef] < 0x0800 && tableSize[(int)TableIndices.Param] < 0x0800 && tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 && tableSize[(int)TableIndices.MemberRef] < 0x0800 && tableSize[(int)TableIndices.Module] < 0x0800 && tableSize[(int)TableIndices.DeclSecurity] < 0x0800 && tableSize[(int)TableIndices.Property] < 0x0800 && tableSize[(int)TableIndices.Event] < 0x0800 && tableSize[(int)TableIndices.StandAloneSig] < 0x0800 && tableSize[(int)TableIndices.ModuleRef] < 0x0800 && tableSize[(int)TableIndices.TypeSpec] < 0x0800 && tableSize[(int)TableIndices.Assembly] < 0x0800 && tableSize[(int)TableIndices.File] < 0x0800 && tableSize[(int)TableIndices.ExportedType] < 0x0800 && tableSize[(int)TableIndices.ManifestResource] < 0x0800 ? 2 : 4; } int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize = tableSize[(int)TableIndices.Method] < 0x2000 && tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4; int declSecurityParentRefSize = this.declSecurityParentRefSize = tableSize[(int)TableIndices.TypeDef] < 0x4000 && tableSize[(int)TableIndices.Method] < 0x4000 && tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4; int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize = tableSize[(int)TableIndices.Field] < 0x8000 && tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4; int guidRefSize = this.guidRefSize = ((tablesHeader.heapSizes & 0x02) == 0 ? 2 : 4); int hasSemanticRefSize = this.hasSemanticRefSize = tableSize[(int)TableIndices.Event] < 0x8000 && tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4; int implementationRefSize = this.implementationRefSize = tableSize[(int)TableIndices.File] < 0x4000 && tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4; int methodDefOrRefSize = this.methodDefOrRefSize = tableSize[(int)TableIndices.Method] < 0x8000 && tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4; int memberRefParentSize = this.memberRefParentSize = tableSize[(int)TableIndices.TypeDef] < 0x2000 && tableSize[(int)TableIndices.TypeRef] < 0x2000 && tableSize[(int)TableIndices.ModuleRef] < 0x2000 && tableSize[(int)TableIndices.Method] < 0x2000 && tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4; int memberForwardedRefSize = this.memberForwardedRefSize = tableSize[(int)TableIndices.Field] < 0x8000 && tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4; int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize = tableSize[(int)TableIndices.TypeDef] < 0x8000 && tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4; int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize = tableSize[(int)TableIndices.TypeDef] < 0x4000 && tableSize[(int)TableIndices.TypeRef] < 0x4000 && tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4; int resolutionScopeRefSize = this.resolutionScopeRefSize = tableSize[(int)TableIndices.Module] < 0x4000 && tableSize[(int)TableIndices.ModuleRef] < 0x4000 && tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4; int stringRefSize = this.stringRefSize = ((tablesHeader.heapSizes & 0x01) == 0 ? 2 : 4); int[] tableOffset = this.tableOffset = new int[(int)TableIndices.Count]; int offset = this.mdOffset + this.tables.offset + 24 + countArray.Length * 4; for (int i = 0; i < (int)TableIndices.Count; i++) { int m = tableSize[i]; if (m == 0) continue; tableOffset[i] = offset; switch ((TableIndices)i) { case TableIndices.Module: offset += m * (2 + stringRefSize + 3 * guidRefSize); break; case TableIndices.TypeRef: offset += m * (resolutionScopeRefSize + 2 * stringRefSize); break; case TableIndices.TypeDef: offset += m * (4 + 2 * stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break; case TableIndices.FieldPtr: offset += m * (tableRefSize[(int)TableIndices.Field]); break; case TableIndices.Field: offset += m * (2 + stringRefSize + blobRefSize); break; case TableIndices.MethodPtr: offset += m * (tableRefSize[(int)TableIndices.Method]); break; case TableIndices.Method: offset += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break; case TableIndices.ParamPtr: offset += m * (tableRefSize[(int)TableIndices.Param]); break; case TableIndices.Param: offset += m * (4 + stringRefSize); break; case TableIndices.InterfaceImpl: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + typeDefOrRefOrSpecSize); break; case TableIndices.MemberRef: offset += m * (memberRefParentSize + stringRefSize + blobRefSize); break; case TableIndices.Constant: offset += m * (2 + constantParentRefSize + blobRefSize); break; case TableIndices.CustomAttribute: offset += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break; case TableIndices.FieldMarshal: offset += m * (fieldMarshalParentRefSize + blobRefSize); break; case TableIndices.DeclSecurity: offset += m * (2 + declSecurityParentRefSize + blobRefSize); break; case TableIndices.ClassLayout: offset += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break; case TableIndices.FieldLayout: offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break; case TableIndices.StandAloneSig: offset += m * (blobRefSize); break; case TableIndices.EventMap: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break; case TableIndices.EventPtr: offset += m * (tableRefSize[(int)TableIndices.Event]); break; case TableIndices.Event: offset += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break; case TableIndices.PropertyMap: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break; case TableIndices.PropertyPtr: offset += m * (tableRefSize[(int)TableIndices.Property]); break; case TableIndices.Property: offset += m * (2 + stringRefSize + blobRefSize); break; case TableIndices.MethodSemantics: offset += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break; case TableIndices.MethodImpl: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + 2 * methodDefOrRefSize); break; case TableIndices.ModuleRef: offset += m * (stringRefSize); break; case TableIndices.TypeSpec: offset += m * (blobRefSize); break; case TableIndices.ImplMap: offset += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break; case TableIndices.FieldRva: offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break; case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered); case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered); case TableIndices.Assembly: offset += m * (16 + blobRefSize + 2 * stringRefSize); break; case TableIndices.AssemblyProcessor: offset += m * (4); break; case TableIndices.AssemblyOS: offset += m * (12); break; case TableIndices.AssemblyRef: offset += m * (12 + 2 * blobRefSize + 2 * stringRefSize); break; case TableIndices.AssemblyRefProcessor: offset += m * (4 + tableRefSize[(int)TableIndices.AssemblyRef]); break; case TableIndices.AssemblyRefOS: offset += m * (12 + tableRefSize[(int)TableIndices.AssemblyRef]); break; case TableIndices.File: offset += m * (4 + stringRefSize + blobRefSize); break; case TableIndices.ExportedType: offset += m * (8 + 2 * stringRefSize + implementationRefSize); break; case TableIndices.ManifestResource: offset += m * (8 + stringRefSize + implementationRefSize); break; case TableIndices.NestedClass: offset += m * (2 * tableRefSize[(int)TableIndices.TypeDef]); break; case TableIndices.GenericParam: if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0) offset += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize); else if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1) offset += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize); else offset += m * (4 + typeDefOrMethodDefSize + stringRefSize); break; case TableIndices.MethodSpec: offset += m * (methodDefOrRefSize + blobRefSize); break; case TableIndices.GenericParamConstraint: offset += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break; default: throw new InvalidMetadataException(ExceptionStrings.UnsupportedTableEncountered); } } } internal Win32ResourceList ReadWin32Resources() { Win32ResourceList rs = new Win32ResourceList(); int startPos = this.win32ResourcesOffset; if (startPos < 0) return rs; MemoryCursor c = this.cursor; c.Position = startPos; int sizeOfTypeDirectory = ReadWin32ResourceDirectoryHeader(c); for (int i = 0; i < sizeOfTypeDirectory; i++) { string TypeName = null; int TypeID = c.ReadInt32(); if (TypeID < 0) { MemoryCursor nac = new MemoryCursor(c); nac.Position = startPos + (TypeID & 0x7FFFFFFF); int strLength = nac.ReadUInt16(); TypeName = nac.ReadUTF16(strLength); } int offset = c.ReadInt32(); if (offset >= 0) rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, null, 0, 0)); else { MemoryCursor nc = new MemoryCursor(c); nc.Position = startPos + (offset & 0x7FFFFFFF); int sizeOfNameDirectory = ReadWin32ResourceDirectoryHeader(nc); for (int j = 0; j < sizeOfNameDirectory; j++) { string Name = null; int ID = nc.ReadInt32(); if (ID < 0) { MemoryCursor nac = new MemoryCursor(c); int strLength = nac.ReadUInt16(); Name = nac.ReadUTF16(strLength); } offset = nc.ReadInt32(); if (offset >= 0) rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, Name, ID, 0)); else { MemoryCursor lc = new MemoryCursor(c); lc.Position = startPos + (offset & 0x7FFFFFFF); int sizeOfLanguageDirectory = ReadWin32ResourceDirectoryHeader(lc); for (int k = 0; k < sizeOfLanguageDirectory; k++) { int LanguageID = lc.ReadInt32(); offset = lc.ReadInt32(); rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, Name, ID, LanguageID)); } } } } } return rs; } private static int ReadWin32ResourceDirectoryHeader(MemoryCursor/*!*/ c) { c.ReadInt32(); //Characteristics c.ReadInt32(); //TimeDate stamp c.ReadInt32(); //Version int numberOfNamedEntries = c.ReadUInt16(); int numberOfIdEntries = c.ReadUInt16(); return numberOfNamedEntries + numberOfIdEntries; } private Win32Resource ReadWin32ResourceDataEntry(MemoryCursor/*!*/ c, int position, string TypeName, int TypeID, string Name, int ID, int LanguageID) { Win32Resource rsrc = new Win32Resource(); rsrc.TypeName = TypeName; rsrc.TypeId = TypeID; rsrc.Name = Name; rsrc.Id = ID; rsrc.LanguageId = LanguageID; c = new MemoryCursor(c); c.Position = position; int dataRVA = c.ReadInt32(); int dataSize = c.ReadInt32(); rsrc.CodePage = c.ReadInt32(); c.Position = this.RvaToOffset(dataRVA); rsrc.Data = c.ReadBytes(dataSize); return rsrc; } private void ReadAssemblyTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Assembly]; AssemblyRow[] result = this.assemblyTable = new AssemblyRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Assembly]; for (int i = 0; i < n; i++) { AssemblyRow row; row.HashAlgId = c.ReadInt32(); row.MajorVersion = c.ReadUInt16(); row.MinorVersion = c.ReadUInt16(); row.BuildNumber = c.ReadUInt16(); row.RevisionNumber = c.ReadUInt16(); row.Flags = c.ReadInt32(); row.PublicKey = c.ReadReference(this.blobRefSize); row.Name = c.ReadReference(this.stringRefSize); row.Culture = c.ReadReference(this.stringRefSize); result[i] = row; } } private void ReadAssemblyRefTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.AssemblyRef]; AssemblyRefRow[] result = this.assemblyRefTable = new AssemblyRefRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.AssemblyRef]; for (int i = 0; i < n; i++) { AssemblyRefRow row; row.MajorVersion = c.ReadUInt16(); row.MinorVersion = c.ReadUInt16(); row.BuildNumber = c.ReadUInt16(); row.RevisionNumber = c.ReadUInt16(); row.Flags = c.ReadInt32(); row.PublicKeyOrToken = c.ReadReference(this.blobRefSize); row.Name = c.ReadReference(this.stringRefSize); row.Culture = c.ReadReference(this.stringRefSize); row.HashValue = c.ReadReference(this.blobRefSize); row.AssemblyReference = null; result[i] = row; } } private void ReadClassLayoutTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.ClassLayout]; ClassLayoutRow[] result = this.classLayoutTable = new ClassLayoutRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ClassLayout]; for (int i = 0; i < n; i++) { ClassLayoutRow row; row.PackingSize = c.ReadUInt16(); row.ClassSize = c.ReadInt32(); row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); result[i] = row; } } private void ReadConstantTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Constant]; ConstantRow[] result = this.constantTable = new ConstantRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Constant]; for (int i = 0; i < n; i++) { ConstantRow row; row.Type = c.ReadByte(); c.ReadByte(); row.Parent = c.ReadReference(this.constantParentRefSize); row.Value = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadCustomAttributeTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.CustomAttribute]; CustomAttributeRow[] result = this.customAttributeTable = new CustomAttributeRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.CustomAttribute]; for (int i = 0; i < n; i++) { CustomAttributeRow row; row.Parent = c.ReadReference(this.customAttributeParentRefSize); row.Constructor = c.ReadReference(this.customAttributeConstructorRefSize); row.Value = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadDeclSecurityTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.DeclSecurity]; DeclSecurityRow[] result = this.declSecurityTable = new DeclSecurityRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.DeclSecurity]; for (int i = 0; i < n; i++) { DeclSecurityRow row; row.Action = c.ReadUInt16(); row.Parent = c.ReadReference(this.declSecurityParentRefSize); row.PermissionSet = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadEventMapTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.EventMap]; EventMapRow[] result = this.eventMapTable = new EventMapRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.EventMap]; for (int i = 0; i < n; i++) { EventMapRow row; row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); row.EventList = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]); result[i] = row; } } private void ReadEventPtrTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.EventPtr]; EventPtrRow[] result = this.eventPtrTable = new EventPtrRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.EventPtr]; for (int i = 0; i < n; i++) { EventPtrRow row; row.Event = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]); result[i] = row; } } private void ReadEventTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Event]; EventRow[] result = this.eventTable = new EventRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Event]; for (int i = 0; i < n; i++) { EventRow row; row.Flags = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); row.EventType = c.ReadReference(this.typeDefOrRefOrSpecSize); result[i] = row; } } private void ReadExportedTypeTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.ExportedType]; ExportedTypeRow[] result = this.exportedTypeTable = new ExportedTypeRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ExportedType]; for (int i = 0; i < n; i++) { ExportedTypeRow row; row.Flags = c.ReadInt32(); row.TypeDefId = c.ReadInt32(); row.TypeName = c.ReadReference(this.stringRefSize); row.TypeNamespace = c.ReadReference(this.stringRefSize); row.Implementation = c.ReadReference(this.implementationRefSize); result[i] = row; } } private void ReadFieldTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Field]; FieldRow[] result = this.fieldTable = new FieldRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Field]; for (int i = 0; i < n; i++) { FieldRow row; row.Flags = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); row.Signature = c.ReadReference(this.blobRefSize); row.Field = null; result[i] = row; } } private void ReadFieldLayoutTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.FieldLayout]; FieldLayoutRow[] result = this.fieldLayoutTable = new FieldLayoutRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.FieldLayout]; for (int i = 0; i < n; i++) { FieldLayoutRow row; row.Offset = c.ReadInt32(); row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]); result[i] = row; } } private void ReadFieldMarshalTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.FieldMarshal]; FieldMarshalRow[] result = this.fieldMarshalTable = new FieldMarshalRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.FieldMarshal]; for (int i = 0; i < n; i++) { FieldMarshalRow row; row.Parent = c.ReadReference(this.fieldMarshalParentRefSize); row.NativeType = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadFieldPtrTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.FieldPtr]; FieldPtrRow[] result = this.fieldPtrTable = new FieldPtrRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.FieldPtr]; for (int i = 0; i < n; i++) { FieldPtrRow row; row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]); result[i] = row; } } private void ReadFieldRvaTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.FieldRva]; FieldRvaRow[] result = this.fieldRvaTable = new FieldRvaRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.FieldRva]; for (int i = 0; i < n; i++) { FieldRvaRow row; row.RVA = c.ReadInt32(); row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]); row.TargetSection = 0; //Ignored on reading result[i] = row; } } private void ReadFileTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.File]; FileRow[] result = this.fileTable = new FileRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.File]; for (int i = 0; i < n; i++) { FileRow row; row.Flags = c.ReadInt32(); row.Name = c.ReadReference(this.stringRefSize); row.HashValue = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadGenericParamTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.GenericParam]; GenericParamRow[] result = this.genericParamTable = new GenericParamRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.GenericParam]; bool reallyOldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0; bool oldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1; for (int i = 0; i < n; i++) { GenericParamRow row; row.Number = c.ReadUInt16(); row.Flags = c.ReadUInt16(); row.Owner = c.ReadReference(this.typeDefOrMethodDefSize); row.Name = c.ReadReference(this.stringRefSize); row.GenericParameter = null; if (oldGenericsFileFormat) c.ReadReference(this.typeDefOrRefOrSpecSize); if (reallyOldGenericsFileFormat) c.ReadInt16(); result[i] = row; } } private void ReadGenericParamConstraintTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.GenericParamConstraint]; GenericParamConstraintRow[] result = this.genericParamConstraintTable = new GenericParamConstraintRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.GenericParamConstraint]; for (int i = 0; i < n; i++) { GenericParamConstraintRow row; row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.GenericParam]); row.Constraint = c.ReadReference(this.typeDefOrRefOrSpecSize); result[i] = row; } } private void ReadImplMapTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.ImplMap]; ImplMapRow[] result = this.implMapTable = new ImplMapRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ImplMap]; for (int i = 0; i < n; i++) { ImplMapRow row; row.MappingFlags = c.ReadUInt16(); row.MemberForwarded = c.ReadReference(this.memberForwardedRefSize); row.ImportName = c.ReadReference(this.stringRefSize); row.ImportScope = c.ReadReference(this.tableRefSize[(int)TableIndices.ModuleRef]); result[i] = row; } } private void ReadInterfaceImplTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.InterfaceImpl]; InterfaceImplRow[] result = this.interfaceImplTable = new InterfaceImplRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.InterfaceImpl]; for (int i = 0; i < n; i++) { InterfaceImplRow row; row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); row.Interface = c.ReadReference(this.typeDefOrRefOrSpecSize); result[i] = row; } } private void ReadManifestResourceTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.ManifestResource]; ManifestResourceRow[] result = this.manifestResourceTable = new ManifestResourceRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ManifestResource]; for (int i = 0; i < n; i++) { ManifestResourceRow row; row.Offset = c.ReadInt32(); row.Flags = c.ReadInt32(); row.Name = c.ReadReference(this.stringRefSize); row.Implementation = c.ReadReference(this.implementationRefSize); result[i] = row; } } private void ReadMemberRefTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.MemberRef]; MemberRefRow[] result = this.memberRefTable = new MemberRefRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.MemberRef]; for (int i = 0; i < n; i++) { MemberRefRow row; row.Class = c.ReadReference(this.memberRefParentSize); row.Name = c.ReadReference(this.stringRefSize); row.Signature = c.ReadReference(this.blobRefSize); row.Member = null; row.VarargTypes = null; result[i] = row; } } private void ReadMethodTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.Method]; MethodRow[] result = this.methodTable = new MethodRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Method]; for (int i = 0; i < n; i++) { MethodRow row; row.RVA = c.ReadInt32(); row.ImplFlags = c.ReadUInt16(); row.Flags = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); row.Signature = c.ReadReference(this.blobRefSize); row.ParamList = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]); row.Method = null; result[i] = row; } } private void ReadMethodImplTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.MethodImpl]; MethodImplRow[] result = this.methodImplTable = new MethodImplRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.MethodImpl]; for (int i = 0; i < n; i++) { MethodImplRow row; row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); row.MethodBody = c.ReadReference(this.methodDefOrRefSize); row.MethodDeclaration = c.ReadReference(this.methodDefOrRefSize); result[i] = row; } } private void ReadMethodPtrTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.MethodPtr]; MethodPtrRow[] result = this.methodPtrTable = new MethodPtrRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.MethodPtr]; for (int i = 0; i < n; i++) { MethodPtrRow row; row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]); result[i] = row; } } private void ReadMethodSemanticsTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.MethodSemantics]; MethodSemanticsRow[] result = this.methodSemanticsTable = new MethodSemanticsRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.MethodSemantics]; for (int i = 0; i < n; i++) { MethodSemanticsRow row; row.Semantics = c.ReadUInt16(); row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]); row.Association = c.ReadReference(this.hasSemanticRefSize); result[i] = row; } } private void ReadMethodSpecTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.MethodSpec]; MethodSpecRow[] result = this.methodSpecTable = new MethodSpecRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.MethodSpec]; for (int i = 0; i < n; i++) { MethodSpecRow row; row.Method = c.ReadReference(this.methodDefOrRefSize); row.Instantiation = c.ReadReference(this.blobRefSize); row.InstantiatedMethod = null; result[i] = row; } } private void ReadModuleTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Module]; ModuleRow[] result = this.moduleTable = new ModuleRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Module]; for (int i = 0; i < n; i++) { ModuleRow row; row.Generation = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); row.Mvid = c.ReadReference(this.guidRefSize); row.EncId = c.ReadReference(this.guidRefSize); row.EncBaseId = c.ReadReference(this.guidRefSize); result[i] = row; } } private void ReadModuleRefTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.ModuleRef]; ModuleRefRow[] result = this.moduleRefTable = new ModuleRefRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ModuleRef]; for (int i = 0; i < n; i++) { ModuleRefRow row; row.Name = c.ReadReference(this.stringRefSize); row.Module = null; result[i] = row; } } private void ReadNestedClassTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.NestedClass]; NestedClassRow[] result = this.nestedClassTable = new NestedClassRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.NestedClass]; for (int i = 0; i < n; i++) { NestedClassRow row; row.NestedClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); row.EnclosingClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); result[i] = row; } } private void ReadParamTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Param]; ParamRow[] result = this.paramTable = new ParamRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Param]; for (int i = 0; i < n; i++) { ParamRow row; row.Flags = c.ReadUInt16(); row.Sequence = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); result[i] = row; } } private void ReadParamPtrTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.ParamPtr]; ParamPtrRow[] result = this.paramPtrTable = new ParamPtrRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.ParamPtr]; for (int i = 0; i < n; i++) { ParamPtrRow row; row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]); result[i] = row; } } private void ReadPropertyTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.Property]; PropertyRow[] result = this.propertyTable = new PropertyRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.Property]; for (int i = 0; i < n; i++) { PropertyRow row; row.Flags = c.ReadUInt16(); row.Name = c.ReadReference(this.stringRefSize); row.Signature = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadPropertyMapTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.PropertyMap]; PropertyMapRow[] result = this.propertyMapTable = new PropertyMapRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.PropertyMap]; for (int i = 0; i < n; i++) { PropertyMapRow row; row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]); row.PropertyList = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]); result[i] = row; } } private void ReadPropertyPtrTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.PropertyPtr]; PropertyPtrRow[] result = this.propertyPtrTable = new PropertyPtrRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.PropertyPtr]; for (int i = 0; i < n; i++) { PropertyPtrRow row; row.Property = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]); result[i] = row; } } private void ReadStandAloneSigTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.StandAloneSig]; StandAloneSigRow[] result = this.standAloneSigTable = new StandAloneSigRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.StandAloneSig]; for (int i = 0; i < n; i++) { StandAloneSigRow row; row.Signature = c.ReadReference(this.blobRefSize); result[i] = row; } } private void ReadTypeDefTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.TypeDef]; TypeDefRow[] result = this.typeDefTable = new TypeDefRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.TypeDef]; for (int i = 0; i < n; i++) { TypeDefRow row; row.Flags = c.ReadInt32(); row.Name = c.ReadReference(this.stringRefSize); row.Namespace = c.ReadReference(this.stringRefSize); row.Extends = c.ReadReference(this.typeDefOrRefOrSpecSize); row.FieldList = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]); row.MethodList = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]); row.Type = null; row.NameKey = 0; row.NamespaceId = null; row.NamespaceKey = 0; result[i] = row; } for (int i = 0; i < n; i++) { result[i].NameKey = this.GetIdentifier(result[i].Name).UniqueIdKey; result[i].NamespaceId = this.GetIdentifier(result[i].Namespace); //^ assume result[i].NamespaceId != null; result[i].NamespaceKey = result[i].NamespaceId.UniqueIdKey; } } private void ReadTypeRefTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.TypeRef]; TypeRefRow[] result = this.typeRefTable = new TypeRefRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.TypeRef]; for (int i = 0; i < n; i++) { TypeRefRow row; row.ResolutionScope = c.ReadReference(this.resolutionScopeRefSize); row.Name = c.ReadReference(this.stringRefSize); row.Namespace = c.ReadReference(this.stringRefSize); row.Type = null; result[i] = row; } } private void ReadTypeSpecTable() //^ requires this.tableSize != null; //^ requires this.tableOffset != null; { int n = this.tableSize[(int)TableIndices.TypeSpec]; TypeSpecRow[] result = this.typeSpecTable = new TypeSpecRow[n]; if (n == 0) return; MemoryCursor c = this.cursor; c.Position = this.tableOffset[(int)TableIndices.TypeSpec]; for (int i = 0; i < n; i++) { TypeSpecRow row; row.Signature = c.ReadReference(this.blobRefSize); row.Type = null; result[i] = row; } } internal int GetOffsetToEndOfSection(int virtualAddress) { foreach (SectionHeader section in this.sectionHeaders) if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData) return (section.sizeOfRawData - (virtualAddress - section.virtualAddress)); return -1; } internal bool NoOffsetFor(int virtualAddress) { foreach (SectionHeader section in this.sectionHeaders) if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData) return false; return true; } private int RvaToOffset(int virtualAddress) { foreach (SectionHeader section in this.sectionHeaders) if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData) return (virtualAddress - section.virtualAddress + section.pointerToRawData); throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.UnknownVirtualAddress, virtualAddress)); } private int RvaToOffset(int virtualAddress, out PESection targetSection) { foreach (SectionHeader section in this.sectionHeaders) if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData) { if (section.name == ".tls") targetSection = PESection.TLS; else if (section.name == ".sdata") targetSection = PESection.SData; else targetSection = PESection.Text; return (virtualAddress - section.virtualAddress + section.pointerToRawData); } throw new InvalidMetadataException(String.Format( CultureInfo.CurrentCulture, ExceptionStrings.UnknownVirtualAddress, +virtualAddress)); } private static CLIHeader/*!*/ ReadCLIHeader(MemoryCursor/*!*/ c) { CLIHeader header = new CLIHeader(); header.cb = c.Int32(0); c.SkipInt32(1); header.majorRuntimeVersion = c.UInt16(0); header.minorRuntimeVersion = c.UInt16(1); c.SkipUInt16(2); header.metaData = ReadDirectoryEntry(c); header.flags = c.Int32(0); header.entryPointToken = c.Int32(1); c.SkipInt32(2); header.resources = ReadDirectoryEntry(c); header.strongNameSignature = ReadDirectoryEntry(c); header.codeManagerTable = ReadDirectoryEntry(c); header.vtableFixups = ReadDirectoryEntry(c); header.exportAddressTableJumps = ReadDirectoryEntry(c); if (header.majorRuntimeVersion < 2) throw new InvalidMetadataException(ExceptionStrings.BadCLIHeader); return header; } private static DirectoryEntry ReadDirectoryEntry(MemoryCursor/*!*/ c) { DirectoryEntry entry = new DirectoryEntry(); entry.virtualAddress = c.Int32(0); entry.size = c.Int32(1); c.SkipInt32(2); return entry; } internal static void ReadDOSHeader(MemoryCursor/*!*/ c) { c.Position = 0; int magicNumber = c.UInt16(0); if (magicNumber != 0x5a4d) throw new InvalidMetadataException(ExceptionStrings.BadMagicNumber); c.Position = 0x3c; int ntHeaderOffset = c.Int32(0); c.Position = ntHeaderOffset; } private static MetadataHeader/*!*/ ReadMetadataHeader(MemoryCursor/*!*/ c) { MetadataHeader header = new MetadataHeader(); header.signature = c.ReadInt32(); if (header.signature != 0x424a5342) throw new InvalidMetadataException(ExceptionStrings.BadMetadataHeaderSignature); header.majorVersion = c.ReadUInt16(); header.minorVersion = c.ReadUInt16(); header.reserved = c.ReadInt32(); int len = c.ReadInt32(); header.versionString = c.ReadASCII(len); while (len++ % 4 != 0) c.ReadByte(); header.flags = c.ReadUInt16(); int n = c.ReadUInt16(); StreamHeader[] streamHeaders = header.streamHeaders = new StreamHeader[n]; for (int i = 0; i < n; i++) streamHeaders[i] = ReadStreamHeader(c); return header; } internal static NTHeader/*!*/ ReadNTHeader(MemoryCursor/*!*/ c) { NTHeader header = new NTHeader(); header.signature = c.ReadInt32(); header.machine = c.ReadUInt16(); header.numberOfSections = c.ReadUInt16(); header.timeDateStamp = c.ReadInt32(); header.pointerToSymbolTable = c.ReadInt32(); header.numberOfSymbols = c.ReadInt32(); header.sizeOfOptionalHeader = c.ReadUInt16(); header.characteristics = c.ReadUInt16(); header.magic = c.ReadUInt16(); header.majorLinkerVersion = c.ReadByte(); header.minorLinkerVersion = c.ReadByte(); header.sizeOfCode = c.ReadInt32(); header.sizeOfInitializedData = c.ReadInt32(); header.sizeOfUninitializedData = c.ReadInt32(); header.addressOfEntryPoint = c.ReadInt32(); header.baseOfCode = c.ReadInt32(); if (header.magic == 0x10B) { header.baseOfData = c.ReadInt32(); header.imageBase = c.ReadInt32(); } else { header.baseOfData = 0; header.imageBase = c.ReadInt64(); } header.sectionAlignment = c.ReadInt32(); header.fileAlignment = c.ReadInt32(); header.majorOperatingSystemVersion = c.ReadUInt16(); header.minorOperatingSystemVersion = c.ReadUInt16(); header.majorImageVersion = c.ReadUInt16(); header.minorImageVersion = c.ReadUInt16(); header.majorSubsystemVersion = c.ReadUInt16(); header.minorSubsystemVersion = c.ReadUInt16(); header.win32VersionValue = c.ReadInt32(); header.sizeOfImage = c.ReadInt32(); header.sizeOfHeaders = c.ReadInt32(); header.checkSum = c.ReadInt32(); header.subsystem = c.ReadUInt16(); header.dllCharacteristics = c.ReadUInt16(); if (header.magic == 0x10B) { header.sizeOfStackReserve = c.ReadInt32(); header.sizeOfStackCommit = c.ReadInt32(); header.sizeOfHeapReserve = c.ReadInt32(); header.sizeOfHeapCommit = c.ReadInt32(); } else { header.sizeOfStackReserve = c.ReadInt64(); header.sizeOfStackCommit = c.ReadInt64(); header.sizeOfHeapReserve = c.ReadInt64(); header.sizeOfHeapCommit = c.ReadInt64(); } header.loaderFlags = c.ReadInt32(); header.numberOfDataDirectories = c.ReadInt32(); // Verify that the header signature and magic number are valid if (header.signature != 0x00004550 /* "PE\0\0" */) throw new InvalidMetadataException(ExceptionStrings.BadCOFFHeaderSignature); if (header.magic != 0x010B && header.magic != 0x020B) throw new InvalidMetadataException(ExceptionStrings.BadPEHeaderMagicNumber); //Read the data directories header.exportTable = ReadDirectoryEntry(c); header.importTable = ReadDirectoryEntry(c); header.resourceTable = ReadDirectoryEntry(c); header.exceptionTable = ReadDirectoryEntry(c); header.certificateTable = ReadDirectoryEntry(c); header.baseRelocationTable = ReadDirectoryEntry(c); header.debugTable = ReadDirectoryEntry(c); header.copyrightTable = ReadDirectoryEntry(c); header.globalPointerTable = ReadDirectoryEntry(c); header.threadLocalStorageTable = ReadDirectoryEntry(c); header.loadConfigTable = ReadDirectoryEntry(c); header.boundImportTable = ReadDirectoryEntry(c); header.importAddressTable = ReadDirectoryEntry(c); header.delayImportTable = ReadDirectoryEntry(c); header.cliHeaderTable = ReadDirectoryEntry(c); header.reserved = ReadDirectoryEntry(c); return header; } internal static SectionHeader ReadSectionHeader(MemoryCursor/*!*/ c) { SectionHeader header = new SectionHeader(); header.name = c.ReadASCII(8); header.virtualSize = c.Int32(0); header.virtualAddress = c.Int32(1); header.sizeOfRawData = c.Int32(2); header.pointerToRawData = c.Int32(3); header.pointerToRelocations = c.Int32(4); header.pointerToLinenumbers = c.Int32(5); c.SkipInt32(6); header.numberOfRelocations = c.UInt16(0); header.numberOfLinenumbers = c.UInt16(1); c.SkipInt16(2); header.characteristics = c.Int32(0); c.SkipInt32(1); return header; } private static StreamHeader ReadStreamHeader(MemoryCursor/*!*/ c) { StreamHeader header = new StreamHeader(); header.offset = c.ReadInt32(); header.size = c.ReadInt32(); header.name = c.ReadASCII(); int n = header.name.Length + 1; c.Position += (4 - (n % 4)) % 4; return header; } private static TablesHeader/*!*/ ReadTablesHeader(MemoryCursor/*!*/ c) { TablesHeader header = new TablesHeader(); header.reserved = c.ReadInt32(); // Must be zero header.majorVersion = c.ReadByte(); // Must be one header.minorVersion = c.ReadByte(); // Must be zero header.heapSizes = c.ReadByte(); // Bits for heap sizes header.rowId = c.ReadByte(); // log-base-2 of largest rowId header.maskValid = c.ReadInt64(); // Present table counts header.maskSorted = c.ReadInt64(); // Sorted tables int n = 0; ulong mask = (ulong)header.maskValid; while (mask != 0) { if (mask % 2 == 1) n++; mask /= 2; } int[] countArray = header.countArray = new int[n]; for (int i = 0; i < n; i++) countArray[i] = c.ReadInt32(); return header; } } #if !NoWriter internal class MetadataWriter { internal MemoryStream StringHeap; internal MemoryStream BlobHeap; internal MemoryStream UserstringHeap; internal MemoryStream ResourceDataHeap; internal MemoryStream SdataHeap; internal MemoryStream TlsHeap; internal Guid[] GuidHeap; internal MemoryStream MethodBodiesHeap; internal Win32ResourceList Win32Resources; internal AssemblyRow[] assemblyTable; internal AssemblyRefRow[] assemblyRefTable; internal ClassLayoutRow[] classLayoutTable; internal ConstantRow[] constantTable; internal CustomAttributeRow[] customAttributeTable; internal DeclSecurityRow[] declSecurityTable; internal EventMapRow[] eventMapTable; internal EventRow[] eventTable; internal ExportedTypeRow[] exportedTypeTable = null; internal FieldRow[] fieldTable; internal FieldLayoutRow[] fieldLayoutTable; internal FieldMarshalRow[] fieldMarshalTable = null; internal FieldRvaRow[] fieldRvaTable = null; internal FileRow[] fileTable; internal GenericParamRow[] genericParamTable; internal GenericParamConstraintRow[] genericParamConstraintTable; internal ImplMapRow[] implMapTable; internal InterfaceImplRow[] interfaceImplTable; internal ManifestResourceRow[] manifestResourceTable = null; internal MemberRefRow[] memberRefTable; internal MethodRow[] methodTable; internal MethodImplRow[] methodImplTable; internal MethodSemanticsRow[] methodSemanticsTable; internal MethodSpecRow[] methodSpecTable; internal ModuleRow[] moduleTable; internal ModuleRefRow[] moduleRefTable; internal NestedClassRow[] nestedClassTable; internal ParamRow[] paramTable; internal PropertyRow[] propertyTable; internal PropertyMapRow[] propertyMapTable; internal StandAloneSigRow[] standAloneSigTable; internal TypeDefRow[] typeDefTable; internal TypeRefRow[] typeRefTable; internal TypeSpecRow[] typeSpecTable; internal int entryPointToken; internal int fileAlignment; internal ModuleKindFlags moduleKind; internal PEKindFlags peKind; internal bool TrackDebugData; internal bool UseGenerics = false; internal byte[] PublicKey; private int blobRefSize; private int constantParentRefSize; private int customAttributeParentRefSize; private int customAttributeConstructorRefSize; private int declSecurityParentRefSize; private int fieldMarshalParentRefSize; private int guidRefSize; private int hasSemanticRefSize; private int implementationRefSize; private int methodDefOrRefSize; private int memberRefParentSize; private int memberForwardedRefSize; private int typeDefOrMethodDefSize; private int typeDefOrRefOrSpecSize; private int resolutionScopeRefSize; private int stringRefSize; #if !ROTOR private ISymUnmanagedWriter symWriter; #endif private int[] tableRefSize; private int[] tableSize; private long validMask; #if !ROTOR internal MetadataWriter(ISymUnmanagedWriter symWriter) { this.symWriter = symWriter; } #else internal MetadataWriter(){ } #endif private void SerializeMetadata(BinaryWriter/*!*/ writer, int virtualAddressBase, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup) //^ requires this.MethodBodiesHeap != null; //^ requires this.ResourceDataHeap != null; //^ requires this.StringHeap != null; //^ requires this.UserstringHeap != null; //^ requires this.BlobHeap != null; //^ requires this.GuidHeap != null; //^ requires TargetPlatform.TargetRuntimeVersion != null; { int tableOffset = 0; tableOffset += (int)this.MethodBodiesHeap.Length; this.MethodBodiesHeap.WriteTo(writer.BaseStream); while (tableOffset % 4 != 0) { writer.Write((byte)0); tableOffset++; } if (this.PublicKey != null && 0 < this.PublicKey.Length) { this.cliHeader.strongNameSignature.virtualAddress = virtualAddressBase + 72 + tableOffset; int keysize = this.PublicKey.Length - 32; if (keysize < 128) keysize = 128; this.cliHeader.strongNameSignature.size = keysize; tableOffset += keysize; writer.BaseStream.Position += keysize; } if (this.ResourceDataHeap.Length > 0) { this.cliHeader.resources.virtualAddress = virtualAddressBase + 72 + tableOffset; this.ResourceDataHeap.WriteTo(writer.BaseStream); int sizeOfResources = (int)this.ResourceDataHeap.Length; while (sizeOfResources % 4 != 0) { writer.Write((byte)0); sizeOfResources++; } this.cliHeader.resources.size = sizeOfResources; tableOffset += sizeOfResources; } this.cliHeader.metaData.virtualAddress = virtualAddressBase + 72 + tableOffset; int startPos = (int)writer.BaseStream.Position; writer.Write((int)0x424a5342); //Magic signature writer.Write((short)1); //Major version writer.Write((short)1); //Minor version writer.Write((int)0); //Reserved writer.Write((int)12); // version must be 12 chars char[] version = new char[12]; char[] aversion = TargetPlatform.TargetRuntimeVersion.ToCharArray(); Array.Copy(aversion, 0, version, 0, Math.Min(12, aversion.Length)); writer.Write(version); writer.Write((short)0); //flags writer.Write((short)5); //number of streams int offsetFromStartOfMetadata = 108; writer.Write((int)offsetFromStartOfMetadata); int cbStringHeapPad = 0; offsetFromStartOfMetadata += (int)this.StringHeap.Length; while (offsetFromStartOfMetadata % 4 != 0) { offsetFromStartOfMetadata++; cbStringHeapPad++; } writer.Write((int)this.StringHeap.Length + cbStringHeapPad); writer.Write(new char[] { '#', 'S', 't', 'r', 'i', 'n', 'g', 's', '\0', '\0', '\0', '\0' }); writer.Write((int)offsetFromStartOfMetadata); offsetFromStartOfMetadata += (int)this.UserstringHeap.Length; int cbUserStringHeapPad = 0; while (offsetFromStartOfMetadata % 4 != 0) { offsetFromStartOfMetadata++; cbUserStringHeapPad++; } writer.Write((int)this.UserstringHeap.Length + cbUserStringHeapPad); writer.Write(new char[] { '#', 'U', 'S', '\0' }); writer.Write((int)offsetFromStartOfMetadata); writer.Write((int)this.BlobHeap.Length); writer.Write(new char[] { '#', 'B', 'l', 'o', 'b', '\0', '\0', '\0' }); offsetFromStartOfMetadata += (int)this.BlobHeap.Length; while (offsetFromStartOfMetadata % 4 != 0) offsetFromStartOfMetadata++; writer.Write((int)offsetFromStartOfMetadata); writer.Write((int)this.GuidHeap.Length * 16); writer.Write(new char[] { '#', 'G', 'U', 'I', 'D', '\0', '\0', '\0' }); offsetFromStartOfMetadata += this.GuidHeap.Length * 16; writer.Write((int)offsetFromStartOfMetadata); int tabsL = this.TablesLength(); writer.Write((int)tabsL); writer.Write(new char[] { '#', '~', '\0', '\0' }); this.StringHeap.WriteTo(writer.BaseStream); int p = (int)this.StringHeap.Length;// +cbStringHeapPad; while (p % 4 != 0) { writer.Write((byte)0); p++; } this.UserstringHeap.WriteTo(writer.BaseStream); p = (int)this.UserstringHeap.Length;// +cbUserStringHeapPad; while (p % 4 != 0) { writer.Write((byte)0); p++; } this.BlobHeap.WriteTo(writer.BaseStream); p = (int)this.BlobHeap.Length; while (p % 4 != 0) { writer.Write((byte)0); p++; } for (int i = 0, n = this.GuidHeap.Length; i < n; i++) writer.Write(this.GuidHeap[i].ToByteArray()); this.SerializeTables(writer, virtualAddressBase + 72, sdataFixup, tlsFixup); this.cliHeader.metaData.size = ((int)writer.BaseStream.Position) - startPos; } #if !ROTOR private unsafe void WriteReferenceToPDBFile(BinaryWriter/*!*/ writer, int virtualAddressBase, int fileBase) //^ requires this.symWriter != null; { int startPos = writer.BaseStream.Position; this.ntHeader.debugTable.virtualAddress = startPos - fileBase + virtualAddressBase; this.ntHeader.debugTable.size = 28; ImageDebugDirectory debugDir = new ImageDebugDirectory(true); uint pcData = 0; this.symWriter.GetDebugInfo(ref debugDir, 0, out pcData, IntPtr.Zero); byte[] data = new byte[pcData]; fixed (byte* pb = data) { this.symWriter.GetDebugInfo(ref debugDir, pcData, out pcData, (IntPtr)pb); } writer.Write((int)debugDir.Characteristics); writer.Write(this.ntHeader.timeDateStamp); writer.Write((ushort)debugDir.MajorVersion); writer.Write((ushort)debugDir.MinorVersion); writer.Write((int)debugDir.Type); writer.Write((int)debugDir.SizeOfData); writer.Write((int)startPos + 28 - fileBase + virtualAddressBase); //AddressOfRawData writer.Write((int)startPos + 28); //PointerToRawData writer.Write((byte[])data); } #endif private void SerializeTables(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup) //^ requires this.StringHeap != null; //^ requires this.GuidHeap != null; //^ requires this.BlobHeap != null; //^ requires this.tableSize != null; //^ requires this.tableRefSize != null; { writer.Write((int)0); //Reserved writer.Write((byte)TargetPlatform.MajorVersion); writer.Write((byte)TargetPlatform.MinorVersion); byte heapSizes = 0; if (this.StringHeap.Length >= 0x10000) heapSizes |= 0x01; if (this.GuidHeap.Length >= 0x10000) heapSizes |= 0x02; if (this.BlobHeap.Length >= 0x10000) heapSizes |= 0x04; writer.Write(heapSizes); writer.Write((byte)0); //Reserved writer.Write(this.validMask); //Tables that are present if (this.UseGenerics) writer.Write((long)0x16003301fa00); //Tables that are sorted else writer.Write((long)0x02003301fa00); //Tables that are sorted int[] tableSize = this.tableSize; for (int i = 0, n = 0; i < (int)TableIndices.Count; i++) if ((n = tableSize[i]) > 0) writer.Write(n); if (this.moduleTable != null) this.SerializeModuleTable(writer); if (this.typeRefTable != null) this.SerializeTypeRefTable(writer); if (this.typeDefTable != null) this.SerializeTypeDefTable(writer); if (this.fieldTable != null) this.SerializeFieldTable(writer); if (this.methodTable != null) this.SerializeMethodTable(writer, mbRVAOffset); if (this.paramTable != null) this.SerializeParamTable(writer); if (this.interfaceImplTable != null) this.SerializeInterfaceImplTable(writer); if (this.memberRefTable != null) this.SerializeMemberRefTable(writer); if (this.constantTable != null) this.SerializeConstantTable(writer); if (this.customAttributeTable != null) this.SerializeCustomAttributeTable(writer); if (this.fieldMarshalTable != null) this.SerializeFieldMarshalTable(writer); if (this.declSecurityTable != null) this.SerializeDeclSecurityTable(writer); if (this.classLayoutTable != null) this.SerializeClassLayoutTable(writer); if (this.fieldLayoutTable != null) this.SerializeFieldLayoutTable(writer); if (this.standAloneSigTable != null) this.SerializeStandAloneSigTable(writer); if (this.eventMapTable != null) this.SerializeEventMapTable(writer); if (this.eventTable != null) this.SerializeEventTable(writer); if (this.propertyMapTable != null) this.SerializePropertyMapTable(writer); if (this.propertyTable != null) this.SerializePropertyTable(writer); if (this.methodSemanticsTable != null) this.SerializeMethodSemanticsTable(writer); if (this.methodImplTable != null) this.SerializeMethodImplTable(writer); if (this.moduleRefTable != null) this.SerializeModuleRefTable(writer); if (this.typeSpecTable != null) this.SerializeTypeSpecTable(writer); if (this.implMapTable != null) this.SerializeImplMapTable(writer); if (this.fieldRvaTable != null) this.SerializeFieldRvaTable(writer, mbRVAOffset, sdataFixup, tlsFixup); if (this.assemblyTable != null) this.SerializeAssemblyTable(writer); if (this.assemblyRefTable != null) this.SerializeAssemblyRefTable(writer); if (this.fileTable != null) this.SerializeFileTable(writer); if (this.exportedTypeTable != null) this.SerializeExportedTypeTable(writer); if (this.manifestResourceTable != null) this.SerializeManifestResourceTable(writer); if (this.nestedClassTable != null) this.SerializeNestedClassTable(writer); if (this.genericParamTable != null) this.SerializeGenericParamTable(writer); if (this.methodSpecTable != null) this.SerializeMethodSpecTable(writer); if (this.genericParamConstraintTable != null) this.SerializeGenericParamConstraintTable(writer); } private void SerializeAssemblyTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.assemblyTable != null; { int n = this.tableSize[(int)TableIndices.Assembly]; for (int i = 0; i < n; i++) { AssemblyRow row = this.assemblyTable[i]; writer.Write((int)row.HashAlgId); writer.Write((short)row.MajorVersion); writer.Write((short)row.MinorVersion); writer.Write((short)row.BuildNumber); writer.Write((short)row.RevisionNumber); writer.Write((int)row.Flags); this.WriteReference(writer, row.PublicKey, this.blobRefSize); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Culture, this.stringRefSize); } } private void SerializeAssemblyRefTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.assemblyRefTable != null; { int n = this.tableSize[(int)TableIndices.AssemblyRef]; for (int i = 0; i < n; i++) { AssemblyRefRow row = this.assemblyRefTable[i]; writer.Write((short)row.MajorVersion); writer.Write((short)row.MinorVersion); writer.Write((short)row.BuildNumber); writer.Write((short)row.RevisionNumber); writer.Write((int)row.Flags); this.WriteReference(writer, row.PublicKeyOrToken, this.blobRefSize); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Culture, this.stringRefSize); this.WriteReference(writer, row.HashValue, this.blobRefSize); } } private void SerializeClassLayoutTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.classLayoutTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.ClassLayout]; for (int i = 0; i < n; i++) { ClassLayoutRow row = this.classLayoutTable[i]; writer.Write((short)row.PackingSize); writer.Write((int)row.ClassSize); this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]); } } private void SerializeConstantTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.constantTable != null; { int n = this.tableSize[(int)TableIndices.Constant]; for (int i = 0; i < n; i++) { ConstantRow row = this.constantTable[i]; writer.Write((byte)row.Type); writer.Write((byte)0); this.WriteReference(writer, row.Parent, this.constantParentRefSize); this.WriteReference(writer, row.Value, this.blobRefSize); } } private void SerializeCustomAttributeTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.customAttributeTable != null; { int n = this.tableSize[(int)TableIndices.CustomAttribute]; for (int i = 0; i < n; i++) { CustomAttributeRow row = this.customAttributeTable[i]; this.WriteReference(writer, row.Parent, this.customAttributeParentRefSize); this.WriteReference(writer, row.Constructor, this.customAttributeConstructorRefSize); this.WriteReference(writer, row.Value, this.blobRefSize); } } private void SerializeDeclSecurityTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.declSecurityTable != null; { int n = this.tableSize[(int)TableIndices.DeclSecurity]; for (int i = 0; i < n; i++) { DeclSecurityRow row = this.declSecurityTable[i]; writer.Write((short)row.Action); this.WriteReference(writer, row.Parent, this.declSecurityParentRefSize); this.WriteReference(writer, row.PermissionSet, this.blobRefSize); } } private void SerializeEventMapTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.eventMapTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.EventMap]; for (int i = 0; i < n; i++) { EventMapRow row = this.eventMapTable[i]; this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]); this.WriteReference(writer, row.EventList, this.tableRefSize[(int)TableIndices.Event]); } } private void SerializeEventTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.eventTable != null; { int n = this.tableSize[(int)TableIndices.Event]; for (int i = 0; i < n; i++) { EventRow row = this.eventTable[i]; writer.Write((short)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.EventType, this.typeDefOrRefOrSpecSize); } } private void SerializeExportedTypeTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.exportedTypeTable != null; { int n = this.tableSize[(int)TableIndices.ExportedType]; for (int i = 0; i < n; i++) { ExportedTypeRow row = this.exportedTypeTable[i]; writer.Write((int)row.Flags); writer.Write((int)row.TypeDefId); this.WriteReference(writer, row.TypeName, this.stringRefSize); this.WriteReference(writer, row.TypeNamespace, this.stringRefSize); this.WriteReference(writer, row.Implementation, this.implementationRefSize); } } private void SerializeFieldTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.fieldTable != null; { int n = this.tableSize[(int)TableIndices.Field]; for (int i = 0; i < n; i++) { FieldRow row = this.fieldTable[i]; writer.Write((short)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Signature, this.blobRefSize); } } private void SerializeFieldLayoutTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.fieldLayoutTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.FieldLayout]; for (int i = 0; i < n; i++) { FieldLayoutRow row = this.fieldLayoutTable[i]; writer.Write((int)row.Offset); this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]); } } private void SerializeFieldMarshalTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.fieldMarshalTable != null; { int n = this.tableSize[(int)TableIndices.FieldMarshal]; for (int i = 0; i < n; i++) { FieldMarshalRow row = this.fieldMarshalTable[i]; this.WriteReference(writer, row.Parent, this.fieldMarshalParentRefSize); this.WriteReference(writer, row.NativeType, this.blobRefSize); } } private void SerializeFieldRvaTable(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup) //^ requires this.tableSize != null; //^ requires this.fieldRvaTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.FieldRva]; for (int i = 0; i < n; i++) { FieldRvaRow row = this.fieldRvaTable[i]; switch (row.TargetSection) { case PESection.SData: case PESection.TLS: Fixup fixup = new Fixup(); fixup.fixupLocation = writer.BaseStream.Position; fixup.addressOfNextInstruction = row.RVA; if (row.TargetSection == PESection.SData) { sdataFixup.nextFixUp = fixup; sdataFixup = fixup; } else { sdataFixup.nextFixUp = fixup; sdataFixup = fixup; } writer.Write((int)0); break; case PESection.Text: writer.Write((int)row.RVA + mbRVAOffset); break; } this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]); } } private void SerializeFileTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.fileTable != null; { int n = this.tableSize[(int)TableIndices.File]; for (int i = 0; i < n; i++) { FileRow row = this.fileTable[i]; writer.Write((int)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.HashValue, this.blobRefSize); } } private void SerializeGenericParamTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.genericParamTable != null; { int n = this.tableSize[(int)TableIndices.GenericParam]; bool reallyOldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0; bool oldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1; for (int i = 0; i < n; i++) { GenericParamRow row = this.genericParamTable[i]; writer.Write((short)row.Number); writer.Write((short)row.Flags); this.WriteReference(writer, row.Owner, this.typeDefOrMethodDefSize); this.WriteReference(writer, row.Name, this.stringRefSize); if (oldGenericsFileFormat) this.WriteReference(writer, 0, this.typeDefOrRefOrSpecSize); if (reallyOldGenericsFileFormat) writer.Write((short)0); } } private void SerializeGenericParamConstraintTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.genericParamConstraintTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.GenericParamConstraint]; for (int i = 0; i < n; i++) { GenericParamConstraintRow row = this.genericParamConstraintTable[i]; this.WriteReference(writer, row.Param, this.tableRefSize[(int)TableIndices.GenericParam]); this.WriteReference(writer, row.Constraint, this.typeDefOrRefOrSpecSize); } } private void SerializeImplMapTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.implMapTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.ImplMap]; for (int i = 0; i < n; i++) { ImplMapRow row = this.implMapTable[i]; writer.Write((short)row.MappingFlags); this.WriteReference(writer, row.MemberForwarded, this.memberForwardedRefSize); this.WriteReference(writer, row.ImportName, this.stringRefSize); this.WriteReference(writer, row.ImportScope, this.tableRefSize[(int)TableIndices.ModuleRef]); } } private void SerializeInterfaceImplTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.interfaceImplTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.InterfaceImpl]; for (int i = 0; i < n; i++) { InterfaceImplRow row = this.interfaceImplTable[i]; this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]); this.WriteReference(writer, row.Interface, this.typeDefOrRefOrSpecSize); } } private void SerializeManifestResourceTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.manifestResourceTable != null; { int n = this.tableSize[(int)TableIndices.ManifestResource]; for (int i = 0; i < n; i++) { ManifestResourceRow row = this.manifestResourceTable[i]; writer.Write((int)row.Offset); writer.Write((int)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Implementation, this.implementationRefSize); } } private void SerializeMemberRefTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.memberRefTable != null; { int n = this.tableSize[(int)TableIndices.MemberRef]; for (int i = 0; i < n; i++) { MemberRefRow row = this.memberRefTable[i]; this.WriteReference(writer, row.Class, this.memberRefParentSize); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Signature, this.blobRefSize); } } private void SerializeMethodTable(BinaryWriter/*!*/ writer, int mbRVAOffset) //^ requires this.tableSize != null; //^ requires this.methodTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.Method]; int pn = this.paramTable == null ? 1 : this.paramTable.Length + 1; for (int i = n - 1; i >= 0; i--) { MethodRow row = this.methodTable[i]; if (row.ParamList != 0) pn = row.ParamList; else this.methodTable[i].ParamList = pn; } for (int i = 0; i < n; i++) { MethodRow row = this.methodTable[i]; if (row.RVA < 0) writer.Write((int)0); else writer.Write((int)row.RVA + mbRVAOffset); writer.Write((short)row.ImplFlags); writer.Write((short)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Signature, this.blobRefSize); this.WriteReference(writer, row.ParamList, this.tableRefSize[(int)TableIndices.Param]); } } private void SerializeMethodImplTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.methodImplTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.MethodImpl]; for (int i = 0; i < n; i++) { MethodImplRow row = this.methodImplTable[i]; this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]); this.WriteReference(writer, row.MethodBody, this.methodDefOrRefSize); this.WriteReference(writer, row.MethodDeclaration, this.methodDefOrRefSize); } } private void SerializeMethodSemanticsTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.methodSemanticsTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.MethodSemantics]; for (int i = 0; i < n; i++) { MethodSemanticsRow row = this.methodSemanticsTable[i]; writer.Write((short)row.Semantics); this.WriteReference(writer, row.Method, this.tableRefSize[(int)TableIndices.Method]); this.WriteReference(writer, row.Association, this.hasSemanticRefSize); } } private void SerializeMethodSpecTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.assemblyTable != null; //^ requires this.methodSpecTable != null; { int n = this.tableSize[(int)TableIndices.MethodSpec]; for (int i = 0; i < n; i++) { MethodSpecRow row = this.methodSpecTable[i]; this.WriteReference(writer, row.Method, this.methodDefOrRefSize); this.WriteReference(writer, row.Instantiation, this.blobRefSize); } } private void SerializeModuleTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.moduleTable != null; { int n = this.tableSize[(int)TableIndices.Module]; for (int i = 0; i < n; i++) { ModuleRow row = this.moduleTable[i]; writer.Write((short)row.Generation); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Mvid, this.guidRefSize); this.WriteReference(writer, row.EncId, this.guidRefSize); this.WriteReference(writer, row.EncBaseId, this.guidRefSize); } } private void SerializeModuleRefTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.moduleRefTable != null; { int n = this.tableSize[(int)TableIndices.ModuleRef]; for (int i = 0; i < n; i++) { ModuleRefRow row = this.moduleRefTable[i]; this.WriteReference(writer, row.Name, this.stringRefSize); } } private void SerializeNestedClassTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.nestedClassTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.NestedClass]; for (int i = 0; i < n; i++) { NestedClassRow row = this.nestedClassTable[i]; this.WriteReference(writer, row.NestedClass, this.tableRefSize[(int)TableIndices.TypeDef]); this.WriteReference(writer, row.EnclosingClass, this.tableRefSize[(int)TableIndices.TypeDef]); } } private void SerializeParamTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.paramTable != null; { int n = this.tableSize[(int)TableIndices.Param]; for (int i = 0; i < n; i++) { ParamRow row = this.paramTable[i]; writer.Write((short)row.Flags); writer.Write((short)row.Sequence); this.WriteReference(writer, row.Name, this.stringRefSize); } } private void SerializePropertyTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.propertyTable != null; { int n = this.tableSize[(int)TableIndices.Property]; for (int i = 0; i < n; i++) { PropertyRow row = this.propertyTable[i]; writer.Write((short)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Signature, this.blobRefSize); } } private void SerializePropertyMapTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.propertyMapTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.PropertyMap]; for (int i = 0; i < n; i++) { PropertyMapRow row = this.propertyMapTable[i]; this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]); this.WriteReference(writer, row.PropertyList, this.tableRefSize[(int)TableIndices.Property]); } } private void SerializeStandAloneSigTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.assemblyTable != null; //^ requires this.standAloneSigTable != null; { int n = this.tableSize[(int)TableIndices.StandAloneSig]; for (int i = 0; i < n; i++) { StandAloneSigRow row = this.standAloneSigTable[i]; this.WriteReference(writer, row.Signature, this.blobRefSize); } } private void SerializeTypeDefTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.typeDefTable != null; //^ requires this.tableRefSize != null; { int n = this.tableSize[(int)TableIndices.TypeDef]; int fn = this.fieldTable == null ? 1 : this.fieldTable.Length + 1; int mn = this.methodTable == null ? 1 : this.methodTable.Length + 1; for (int i = n - 1; i >= 0; i--) { TypeDefRow row = this.typeDefTable[i]; if (row.FieldList != 0) fn = row.FieldList; else this.typeDefTable[i].FieldList = fn; if (row.MethodList != 0) mn = row.MethodList; else this.typeDefTable[i].MethodList = mn; } for (int i = 0; i < n; i++) { TypeDefRow row = this.typeDefTable[i]; writer.Write((int)row.Flags); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Namespace, this.stringRefSize); this.WriteReference(writer, row.Extends, this.typeDefOrRefOrSpecSize); this.WriteReference(writer, row.FieldList, this.tableRefSize[(int)TableIndices.Field]); this.WriteReference(writer, row.MethodList, this.tableRefSize[(int)TableIndices.Method]); } } private void SerializeTypeRefTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.typeRefTable != null; { int n = this.tableSize[(int)TableIndices.TypeRef]; for (int i = 0; i < n; i++) { TypeRefRow row = this.typeRefTable[i]; this.WriteReference(writer, row.ResolutionScope, this.resolutionScopeRefSize); this.WriteReference(writer, row.Name, this.stringRefSize); this.WriteReference(writer, row.Namespace, this.stringRefSize); } } private void SerializeTypeSpecTable(BinaryWriter/*!*/ writer) //^ requires this.tableSize != null; //^ requires this.typeSpecTable != null; { int n = this.tableSize[(int)TableIndices.TypeSpec]; for (int i = 0; i < n; i++) { TypeSpecRow row = this.typeSpecTable[i]; this.WriteReference(writer, row.Signature, this.blobRefSize); } } private int TablesLength() //^ requires this.BlobHeap != null; //^ requires this.GuidHeap != null; //^ requires this.StringHeap != null; { int[] tableSize = this.tableSize = new int[(int)TableIndices.Count]; int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count]; int tableCount = 0; long validMask = 0; for (int i = 0; i < (int)TableIndices.Count; i++) { int j = 0; switch ((TableIndices)i) { case TableIndices.Module: if (this.moduleTable != null) j = this.moduleTable.Length; break; case TableIndices.TypeRef: if (this.typeRefTable != null) j = this.typeRefTable.Length; break; case TableIndices.TypeDef: if (this.typeDefTable != null) j = this.typeDefTable.Length; break; case TableIndices.Field: if (this.fieldTable != null) j = this.fieldTable.Length; break; case TableIndices.Method: if (this.methodTable != null) j = this.methodTable.Length; break; case TableIndices.Param: if (this.paramTable != null) j = this.paramTable.Length; break; case TableIndices.InterfaceImpl: if (this.interfaceImplTable != null) j = this.interfaceImplTable.Length; break; case TableIndices.MemberRef: if (this.memberRefTable != null) j = this.memberRefTable.Length; break; case TableIndices.Constant: if (this.constantTable != null) j = this.constantTable.Length; break; case TableIndices.CustomAttribute: if (this.customAttributeTable != null) j = this.customAttributeTable.Length; break; case TableIndices.FieldMarshal: if (this.fieldMarshalTable != null) j = this.fieldMarshalTable.Length; break; case TableIndices.DeclSecurity: if (this.declSecurityTable != null) j = this.declSecurityTable.Length; break; case TableIndices.ClassLayout: if (this.classLayoutTable != null) j = this.classLayoutTable.Length; break; case TableIndices.FieldLayout: if (this.fieldLayoutTable != null) j = this.fieldLayoutTable.Length; break; case TableIndices.StandAloneSig: if (this.standAloneSigTable != null) j = this.standAloneSigTable.Length; break; case TableIndices.EventMap: if (this.eventMapTable != null) j = this.eventMapTable.Length; break; case TableIndices.Event: if (this.eventTable != null) j = this.eventTable.Length; break; case TableIndices.PropertyMap: if (this.propertyMapTable != null) j = this.propertyMapTable.Length; break; case TableIndices.Property: if (this.propertyTable != null) j = this.propertyTable.Length; break; case TableIndices.MethodSemantics: if (this.methodSemanticsTable != null) j = this.methodSemanticsTable.Length; break; case TableIndices.MethodImpl: if (this.methodImplTable != null) j = this.methodImplTable.Length; break; case TableIndices.ModuleRef: if (this.moduleRefTable != null) j = this.moduleRefTable.Length; break; case TableIndices.TypeSpec: if (this.typeSpecTable != null) j = this.typeSpecTable.Length; break; case TableIndices.ImplMap: if (this.implMapTable != null) j = this.implMapTable.Length; break; case TableIndices.FieldRva: if (this.fieldRvaTable != null) j = this.fieldRvaTable.Length; break; case TableIndices.Assembly: if (this.assemblyTable != null) j = this.assemblyTable.Length; break; case TableIndices.AssemblyRef: if (this.assemblyRefTable != null) j = this.assemblyRefTable.Length; break; case TableIndices.File: if (this.fileTable != null) j = this.fileTable.Length; break; case TableIndices.ExportedType: if (this.exportedTypeTable != null) j = this.exportedTypeTable.Length; break; case TableIndices.ManifestResource: if (this.manifestResourceTable != null) j = this.manifestResourceTable.Length; break; case TableIndices.NestedClass: if (this.nestedClassTable != null) j = this.nestedClassTable.Length; break; case TableIndices.GenericParam: if (this.genericParamTable != null) j = this.genericParamTable.Length; break; case TableIndices.MethodSpec: if (this.methodSpecTable != null) j = this.methodSpecTable.Length; break; case TableIndices.GenericParamConstraint: if (this.genericParamConstraintTable != null) j = this.genericParamConstraintTable.Length; break; } tableSize[i] = j; if (j > 0) { tableCount++; validMask |= 1L << i; } } this.validMask = validMask; for (int i = 0; i < (int)TableIndices.Count; i++) tableRefSize[i] = tableSize[i] < 0x10000 ? 2 : 4; int blobRefSize = this.blobRefSize = this.BlobHeap.Length < 0x10000 ? 2 : 4; int constantParentRefSize = this.constantParentRefSize = tableSize[(int)TableIndices.Param] < 0x4000 && tableSize[(int)TableIndices.Field] < 0x4000 && tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4; int customAttributeParentRefSize = this.customAttributeParentRefSize = tableSize[(int)TableIndices.Method] < 0x0800 && tableSize[(int)TableIndices.Field] < 0x0800 && tableSize[(int)TableIndices.TypeRef] < 0x0800 && tableSize[(int)TableIndices.TypeDef] < 0x0800 && tableSize[(int)TableIndices.Param] < 0x0800 && tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 && tableSize[(int)TableIndices.MemberRef] < 0x0800 && tableSize[(int)TableIndices.Module] < 0x0800 && tableSize[(int)TableIndices.DeclSecurity] < 0x0800 && tableSize[(int)TableIndices.Property] < 0x0800 && tableSize[(int)TableIndices.Event] < 0x0800 && tableSize[(int)TableIndices.StandAloneSig] < 0x0800 && tableSize[(int)TableIndices.ModuleRef] < 0x0800 && tableSize[(int)TableIndices.TypeSpec] < 0x0800 && tableSize[(int)TableIndices.Assembly] < 0x0800 && tableSize[(int)TableIndices.File] < 0x0800 && tableSize[(int)TableIndices.ExportedType] < 0x0800 && tableSize[(int)TableIndices.ManifestResource] < 0x0800 && tableSize[(int)TableIndices.GenericParam] < 0x0800 && tableSize[(int)TableIndices.MethodSpec] < 0x0800 && tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4; int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize = tableSize[(int)TableIndices.Method] < 0x2000 && tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4; int declSecurityParentRefSize = this.declSecurityParentRefSize = tableSize[(int)TableIndices.TypeDef] < 0x4000 && tableSize[(int)TableIndices.Method] < 0x4000 && tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4; int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize = tableSize[(int)TableIndices.Field] < 0x8000 && tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4; int guidRefSize = this.guidRefSize = this.GuidHeap.Length < 0x10000 ? 2 : 4; int hasSemanticRefSize = this.hasSemanticRefSize = tableSize[(int)TableIndices.Event] < 0x8000 && tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4; int implementationRefSize = this.implementationRefSize = tableSize[(int)TableIndices.File] < 0x4000 && tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4; int methodDefOrRefSize = this.methodDefOrRefSize = tableSize[(int)TableIndices.Method] < 0x8000 && tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4; int memberRefParentSize = this.memberRefParentSize = tableSize[(int)TableIndices.TypeDef] < 0x2000 && tableSize[(int)TableIndices.TypeRef] < 0x2000 && tableSize[(int)TableIndices.ModuleRef] < 0x2000 && tableSize[(int)TableIndices.Method] < 0x2000 && tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4; int memberForwardedRefSize = this.memberForwardedRefSize = tableSize[(int)TableIndices.Field] < 0x8000 && tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4; int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize = tableSize[(int)TableIndices.TypeDef] < 0x8000 && tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4; int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize = tableSize[(int)TableIndices.TypeDef] < 0x4000 && tableSize[(int)TableIndices.TypeRef] < 0x4000 && tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4; int resolutionScopeRefSize = this.resolutionScopeRefSize = tableSize[(int)TableIndices.Module] < 0x4000 && tableSize[(int)TableIndices.ModuleRef] < 0x4000 && tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4; int stringRefSize = this.stringRefSize = this.StringHeap.Length < 0x10000 ? 2 : 4; int length = 0; for (int i = 0; i < (int)TableIndices.Count; i++) { int m = tableSize[i]; if (m == 0) continue; switch ((TableIndices)i) { case TableIndices.Module: length += m * (2 + stringRefSize + 3 * guidRefSize); break; case TableIndices.TypeRef: length += m * (resolutionScopeRefSize + 2 * stringRefSize); break; case TableIndices.TypeDef: length += m * (4 + 2 * stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break; case TableIndices.Field: length += m * (2 + stringRefSize + blobRefSize); break; case TableIndices.Method: length += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break; case TableIndices.Param: length += m * (4 + stringRefSize); break; case TableIndices.InterfaceImpl: length += m * (tableRefSize[(int)TableIndices.TypeDef] + typeDefOrRefOrSpecSize); break; case TableIndices.MemberRef: length += m * (memberRefParentSize + stringRefSize + blobRefSize); break; case TableIndices.Constant: length += m * (2 + constantParentRefSize + blobRefSize); break; case TableIndices.CustomAttribute: length += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break; case TableIndices.FieldMarshal: length += m * (fieldMarshalParentRefSize + blobRefSize); break; case TableIndices.DeclSecurity: length += m * (2 + declSecurityParentRefSize + blobRefSize); break; case TableIndices.ClassLayout: length += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break; case TableIndices.FieldLayout: length += m * (4 + tableRefSize[(int)TableIndices.Field]); break; case TableIndices.StandAloneSig: length += m * (blobRefSize); break; case TableIndices.EventMap: length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break; case TableIndices.Event: length += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break; case TableIndices.PropertyMap: length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break; case TableIndices.Property: length += m * (2 + stringRefSize + blobRefSize); break; case TableIndices.MethodSemantics: length += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break; case TableIndices.MethodImpl: length += m * (tableRefSize[(int)TableIndices.TypeDef] + 2 * methodDefOrRefSize); break; case TableIndices.ModuleRef: length += m * (stringRefSize); break; case TableIndices.TypeSpec: length += m * (blobRefSize); break; case TableIndices.ImplMap: length += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break; case TableIndices.FieldRva: length += m * (4 + tableRefSize[(int)TableIndices.Field]); break; case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered); case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered); case TableIndices.Assembly: length += m * (16 + blobRefSize + 2 * stringRefSize); break; case TableIndices.AssemblyRef: length += m * (12 + 2 * blobRefSize + 2 * stringRefSize); break; case TableIndices.File: length += m * (4 + stringRefSize + blobRefSize); break; case TableIndices.ExportedType: length += m * (8 + 2 * stringRefSize + implementationRefSize); break; case TableIndices.ManifestResource: length += m * (8 + stringRefSize + implementationRefSize); break; case TableIndices.NestedClass: length += m * (2 * tableRefSize[(int)TableIndices.TypeDef]); break; case TableIndices.GenericParam: if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0) length += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize); else if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1) length += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize); else length += m * (4 + typeDefOrMethodDefSize + stringRefSize); break; case TableIndices.MethodSpec: length += m * (methodDefOrRefSize + blobRefSize); break; case TableIndices.GenericParamConstraint: length += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break; } } length += 24 + (tableCount * 4); return length; } private NTHeader/*!*/ ntHeader = new NTHeader(); private CLIHeader/*!*/ cliHeader = new CLIHeader(); private SectionHeader[] sectionHeaders; internal void WritePE(BinaryWriter/*!*/ writer) //^ requires this.SdataHeap != null; //^ requires this.TlsHeap != null; { this.cliHeader.entryPointToken = this.entryPointToken; switch (this.moduleKind) { case ModuleKindFlags.ConsoleApplication: this.ntHeader.subsystem = 3; break; case ModuleKindFlags.DynamicallyLinkedLibrary: this.ntHeader.characteristics |= 0x2000; this.ntHeader.subsystem = 3; break; case ModuleKindFlags.WindowsApplication: this.ntHeader.subsystem = 2; break; } int numSectionHeaders = 2; if (this.SdataHeap.Length > 0) numSectionHeaders++; if (this.TlsHeap.Length > 0) numSectionHeaders++; if (this.Win32Resources != null && this.Win32Resources.Count > 0) numSectionHeaders++; this.sectionHeaders = new SectionHeader[numSectionHeaders]; this.ntHeader.numberOfSections = (ushort)numSectionHeaders; this.ntHeader.timeDateStamp = (int)((DateTime.Now.ToUniversalTime() - NineteenSeventy).TotalSeconds); //Write out .text section for meta data tables, method bodies, address tables and entry point stub Fixup sdataFixup = new Fixup(); Fixup tlsFixup = new Fixup(); SectionHeader textSection = new SectionHeader(); textSection.name = ".text"; textSection.virtualAddress = 8192; int sizeOfPeHeaders = 376 + 40 * numSectionHeaders; textSection.pointerToRawData = ((int)Math.Ceiling(sizeOfPeHeaders / (double)this.fileAlignment)) * this.fileAlignment; textSection.characteristics = 0x60000020; writer.BaseStream.Position = textSection.pointerToRawData + 72; //Leave 72 bytes for CLI header this.SerializeMetadata(writer, textSection.virtualAddress, sdataFixup, tlsFixup); int RVAofEntryPointJumpTarget = this.WriteImportTableAndEntryPointStub(writer, ref textSection); #if !ROTOR if (this.symWriter != null) this.WriteReferenceToPDBFile(writer, textSection.virtualAddress, textSection.pointerToRawData); #endif int len = textSection.virtualSize = ((int)writer.BaseStream.Position) - textSection.pointerToRawData; textSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment; this.sectionHeaders[0] = textSection; writer.BaseStream.Position = textSection.pointerToRawData; this.ntHeader.cliHeaderTable.virtualAddress = textSection.virtualAddress; this.ntHeader.cliHeaderTable.size = 72; WriteCLIHeader(writer); //Write CLI header last so that forward pointers can be filled in first int sectionHeaderIndex = 1; SectionHeader previousSection = textSection; int n = this.ntHeader.sectionAlignment; int m = this.fileAlignment; if (this.SdataHeap.Length > 0) { SectionHeader sdataSection = new SectionHeader(); sdataSection.name = ".sdata"; int vaddr = sdataSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n); sdataSection.virtualSize = this.SdataHeap.Length; sdataSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m); sdataSection.characteristics = unchecked((int)0xC0000040); writer.BaseStream.Position = sdataSection.pointerToRawData; this.SdataHeap.WriteTo(writer.BaseStream); len = sdataSection.virtualSize = ((int)writer.BaseStream.Position) - sdataSection.pointerToRawData; writer.BaseStream.Position += m - (len % this.fileAlignment) - 1; writer.Write((byte)0); sdataSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment; sdataFixup = sdataFixup.nextFixUp; //Skip over dummy header while (sdataFixup != null) { writer.BaseStream.Position = sdataFixup.fixupLocation; writer.Write((int)(vaddr + sdataFixup.addressOfNextInstruction)); sdataFixup = sdataFixup.nextFixUp; } this.sectionHeaders[sectionHeaderIndex++] = sdataSection; previousSection = sdataSection; } if (this.TlsHeap.Length > 0) { SectionHeader tlsSection = new SectionHeader(); tlsSection.name = ".tls"; int vaddr = tlsSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n); tlsSection.virtualSize = this.SdataHeap.Length; tlsSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m); tlsSection.characteristics = unchecked((int)0xC0000040); writer.BaseStream.Position = tlsSection.pointerToRawData; this.TlsHeap.WriteTo(writer.BaseStream); len = tlsSection.virtualSize = ((int)writer.BaseStream.Position) - tlsSection.pointerToRawData; writer.BaseStream.Position += m - (len % this.fileAlignment) - 1; writer.Write((byte)0); tlsSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment; tlsFixup = tlsFixup.nextFixUp; //Skip over dummy header while (tlsFixup != null) { writer.BaseStream.Position = tlsFixup.fixupLocation; writer.Write((int)(vaddr + tlsFixup.addressOfNextInstruction)); tlsFixup = tlsFixup.nextFixUp; } this.sectionHeaders[sectionHeaderIndex++] = tlsSection; previousSection = tlsSection; } if (this.Win32Resources != null && this.Win32Resources.Count > 0) { SectionHeader rsrcSection = new SectionHeader(); rsrcSection.name = ".rsrc"; rsrcSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n); rsrcSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m); rsrcSection.characteristics = 0x40000040; writer.BaseStream.Position = rsrcSection.pointerToRawData; this.WriteWin32Resources(writer, rsrcSection.virtualAddress); len = rsrcSection.virtualSize = ((int)writer.BaseStream.Position) - rsrcSection.pointerToRawData; writer.BaseStream.Position += m - (len % this.fileAlignment) - 1; writer.Write((byte)0); rsrcSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment; this.sectionHeaders[sectionHeaderIndex++] = rsrcSection; this.ntHeader.resourceTable.virtualAddress = rsrcSection.virtualAddress; this.ntHeader.resourceTable.size = rsrcSection.virtualSize; this.ntHeader.sizeOfInitializedData += rsrcSection.sizeOfRawData; previousSection = rsrcSection; } //Write out .reloc section for entry point stub relocation table SectionHeader relocSection = new SectionHeader(); relocSection.name = ".reloc"; relocSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n); relocSection.virtualSize = 12; relocSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m); relocSection.sizeOfRawData = m; relocSection.characteristics = 0x42000040; writer.BaseStream.Position = relocSection.pointerToRawData; writer.Write((int)((RVAofEntryPointJumpTarget / 4096) * 4096)); //Page RVA writer.Write((int)12); int offsetWithinPage = RVAofEntryPointJumpTarget % 4096; short s = (short)(3 << 12 | offsetWithinPage); writer.Write(s); writer.Write((short)0); //next chunk's RVA writer.BaseStream.Position += m - 13; writer.Write((byte)0); this.sectionHeaders[sectionHeaderIndex] = relocSection; this.ntHeader.baseRelocationTable.virtualAddress = relocSection.virtualAddress; this.ntHeader.baseRelocationTable.size = relocSection.virtualSize; this.ntHeader.sizeOfInitializedData += relocSection.sizeOfRawData; //Write PE headers. Do this last because forward pointers are filled in by preceding code writer.BaseStream.Position = 0; writer.Write(dosHeader); WriteNTHeader(writer); WriteSectionHeaders(writer); } private class Directory { internal string Name; internal int ID; internal int NumberOfNamedEntries; internal int NumberOfIdEntries; internal ArrayList/*!*/ Entries; internal Directory(string Name, int ID) { this.Name = Name; this.ID = ID; this.Entries = new ArrayList(); //^ base(); } } private void WriteWin32Resources(BinaryWriter/*!*/ writer, int virtualAddressBase) //^ requires this.Win32Resources != null; { Win32ResourceList rsrcs = this.Win32Resources; BinaryWriter dataHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode); //Construct a tree of array lists to represent the directory and make it easier to compute offsets Directory TypeDirectory = new Directory("", 0); Directory NameDirectory = null; Directory LanguageDirectory = null; int lastTypeID = int.MinValue; string lastTypeName = null; int lastID = int.MinValue; string lastName = null; int sizeOfDirectoryTree = 16; for (int i = 0, n = rsrcs.Count; i < n; i++) { Win32Resource r = rsrcs[i]; bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; if (typeDifferent) { lastTypeID = r.TypeId; lastTypeName = r.TypeName; if (lastTypeID < 0) TypeDirectory.NumberOfNamedEntries++; else TypeDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 24; TypeDirectory.Entries.Add(NameDirectory = new Directory(lastTypeName, lastTypeID)); } //^ assume NameDirectory != null; if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) { lastID = r.Id; lastName = r.Name; if (lastID < 0) NameDirectory.NumberOfNamedEntries++; else NameDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 24; NameDirectory.Entries.Add(LanguageDirectory = new Directory(lastName, lastID)); } //^ assume LanguageDirectory != null; LanguageDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 8; LanguageDirectory.Entries.Add(r); continue; } this.WriteDirectory(TypeDirectory, writer, 0, 0, sizeOfDirectoryTree, virtualAddressBase, dataHeap); dataHeap.BaseStream.WriteTo(writer.BaseStream); } private void WriteDirectory(Directory/*!*/ directory, BinaryWriter/*!*/ writer, int offset, int level, int sizeOfDirectoryTree, int virtualAddressBase, BinaryWriter/*!*/ dataHeap) { writer.Write((int)0); //Characteristics writer.Write((int)0); //Timestamp writer.Write((int)0); //Version writer.Write((short)directory.NumberOfNamedEntries); writer.Write((short)directory.NumberOfIdEntries); int n = directory.Entries.Count; int k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id = int.MinValue; string name = null; int nOff = dataHeap.BaseStream.Position + sizeOfDirectoryTree; int dOff = k; Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { id = subDir.ID; name = subDir.Name; if (level == 0) k += this.SizeOfDirectory(subDir); else k += 16 + 8 * subDir.Entries.Count; } else { Win32Resource r = (Win32Resource)directory.Entries[i]; id = level == 0 ? r.TypeId : level == 1 ? r.Id : r.LanguageId; name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; dataHeap.Write((int)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataHeap.BaseStream.Position)); dataHeap.Write((int)r.Data.Length); dataHeap.Write((int)r.CodePage); dataHeap.Write((int)0); dataHeap.Write(r.Data); } if (id >= 0) writer.Write(id); else { if (name == null) name = ""; writer.Write(((uint)nOff) | 0x80000000); dataHeap.Write((ushort)name.Length); dataHeap.Write(name.ToCharArray()); //REVIEW: what happens if the name contains chars that do not fit into a single utf8 code point? } if (subDir != null) writer.Write(((uint)dOff) | 0x80000000); else writer.Write(nOff); } k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataHeap); if (level == 0) k += this.SizeOfDirectory(subDir); else k += 16 + 8 * subDir.Entries.Count; } } } private int SizeOfDirectory(Directory/*!*/ directory) { int n = directory.Entries.Count; int size = 16 + 8 * n; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) size += 16 + 8 * subDir.Entries.Count; } return size; } private static readonly byte[] dosHeader = new byte[]{ 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static readonly DateTime NineteenSeventy = new DateTime(1970, 1, 1).ToUniversalTime(); private void WriteNTHeader(BinaryWriter/*!*/ writer) //^ requires this.sectionHeaders != null; { NTHeader ntHeader = this.ntHeader; writer.Write(ntHeader.signature); if ((this.peKind & PEKindFlags.Requires64bits) == 0) { ntHeader.magic = 0x10B; //PE32 ntHeader.machine = 0x014c; //I386 } else { ntHeader.characteristics &= 0xFEFF; //Not 32-bit ntHeader.characteristics |= 0x0020; //Can handle >2gb addresses ntHeader.magic = 0x20B; //PE32+ if ((this.peKind & PEKindFlags.AMD) != 0) ntHeader.machine = 0x8664; //AMD64 else ntHeader.machine = 0x0200; //IA64 ntHeader.sizeOfOptionalHeader += 16; } writer.Write(ntHeader.machine); writer.Write(ntHeader.numberOfSections); writer.Write(ntHeader.timeDateStamp); writer.Write(ntHeader.pointerToSymbolTable); writer.Write(ntHeader.numberOfSymbols); writer.Write(ntHeader.sizeOfOptionalHeader); writer.Write(ntHeader.characteristics); writer.Write(ntHeader.magic); writer.Write((byte)TargetPlatform.LinkerMajorVersion); writer.Write((byte)TargetPlatform.LinkerMinorVersion); writer.Write(this.sectionHeaders[0].sizeOfRawData); //sizeOfCode writer.Write(ntHeader.sizeOfInitializedData); writer.Write(ntHeader.sizeOfUninitializedData); writer.Write(ntHeader.addressOfEntryPoint); writer.Write(this.sectionHeaders[0].virtualAddress); //baseOfCode if (ntHeader.magic == 0x10B) { if (this.sectionHeaders.Length > 1) writer.Write(this.sectionHeaders[1].virtualAddress); //baseOfData else writer.Write((int)0); writer.Write((int)ntHeader.imageBase); } else { writer.Write(ntHeader.imageBase); } writer.Write(ntHeader.sectionAlignment); writer.Write(this.fileAlignment); writer.Write(ntHeader.majorOperatingSystemVersion); writer.Write(ntHeader.minorOperatingSystemVersion); writer.Write(ntHeader.majorImageVersion); writer.Write(ntHeader.minorImageVersion); writer.Write(ntHeader.majorSubsystemVersion); writer.Write(ntHeader.minorSubsystemVersion); writer.Write(ntHeader.win32VersionValue); int sectionPages = (int)(Math.Ceiling(this.sectionHeaders[this.sectionHeaders.Length - 1].virtualSize / (double)ntHeader.sectionAlignment) * ntHeader.sectionAlignment); writer.Write(this.sectionHeaders[this.sectionHeaders.Length - 1].virtualAddress + sectionPages); //sizeOfImage writer.Write(this.sectionHeaders[0].pointerToRawData); //sizeOfHeaders writer.Write(ntHeader.checkSum); writer.Write(ntHeader.subsystem); writer.Write(ntHeader.dllCharacteristics); if (ntHeader.magic == 0x10B) { writer.Write((int)ntHeader.sizeOfStackReserve); writer.Write((int)ntHeader.sizeOfStackCommit); writer.Write((int)ntHeader.sizeOfHeapReserve); writer.Write((int)ntHeader.sizeOfHeapCommit); } else { writer.Write(ntHeader.sizeOfStackReserve); writer.Write(ntHeader.sizeOfStackCommit); writer.Write(ntHeader.sizeOfHeapReserve); writer.Write(ntHeader.sizeOfHeapCommit); } writer.Write(ntHeader.loaderFlags); writer.Write(ntHeader.numberOfDataDirectories); writer.Write(ntHeader.exportTable.virtualAddress); writer.Write(ntHeader.exportTable.size); writer.Write(ntHeader.importTable.virtualAddress); writer.Write(ntHeader.importTable.size); writer.Write(ntHeader.resourceTable.virtualAddress); writer.Write(ntHeader.resourceTable.size); writer.Write(ntHeader.exceptionTable.virtualAddress); writer.Write(ntHeader.exceptionTable.size); writer.Write(ntHeader.certificateTable.virtualAddress); writer.Write(ntHeader.certificateTable.size); writer.Write(ntHeader.baseRelocationTable.virtualAddress); writer.Write(ntHeader.baseRelocationTable.size); writer.Write(ntHeader.debugTable.virtualAddress); writer.Write(ntHeader.debugTable.size); writer.Write(ntHeader.copyrightTable.virtualAddress); writer.Write(ntHeader.copyrightTable.size); writer.Write(ntHeader.globalPointerTable.virtualAddress); writer.Write(ntHeader.globalPointerTable.size); writer.Write(ntHeader.threadLocalStorageTable.virtualAddress); writer.Write(ntHeader.threadLocalStorageTable.size); writer.Write(ntHeader.loadConfigTable.virtualAddress); writer.Write(ntHeader.loadConfigTable.size); writer.Write(ntHeader.boundImportTable.virtualAddress); writer.Write(ntHeader.boundImportTable.size); writer.Write(ntHeader.importAddressTable.virtualAddress); writer.Write(ntHeader.importAddressTable.size); writer.Write(ntHeader.delayImportTable.virtualAddress); writer.Write(ntHeader.delayImportTable.size); writer.Write(ntHeader.cliHeaderTable.virtualAddress); writer.Write(ntHeader.cliHeaderTable.size); writer.Write((long)0); } private void WriteSectionHeaders(BinaryWriter/*!*/ writer) //^ requires this.sectionHeaders != null; { SectionHeader[] sectionHeaders = this.sectionHeaders; for (int i = 0, n = this.sectionHeaders.Length; i < n; i++) { SectionHeader hdr = sectionHeaders[i]; //^ assume hdr.name != null; for (int j = 0, m = hdr.name.Length; j < 8; j++) if (j < m) writer.Write(hdr.name[j]); else writer.Write((byte)0); writer.Write(hdr.virtualSize); writer.Write(hdr.virtualAddress); writer.Write(hdr.sizeOfRawData); writer.Write(hdr.pointerToRawData); writer.Write(hdr.pointerToRelocations); writer.Write(hdr.pointerToLinenumbers); writer.Write(hdr.numberOfRelocations); writer.Write(hdr.numberOfLinenumbers); writer.Write(hdr.characteristics); } } private void WriteCLIHeader(BinaryWriter/*!*/ writer) { CLIHeader hdr = this.cliHeader; writer.Write(hdr.cb); writer.Write((ushort)2); if (this.UseGenerics) writer.Write((ushort)5); //Violates the ECMA standard (25.3.3 of Partition II), but apparently necessary else writer.Write((ushort)0); writer.Write(hdr.metaData.virtualAddress); writer.Write(hdr.metaData.size); if ((this.peKind & PEKindFlags.Requires32bits) != 0) hdr.flags |= 2; if ((this.peKind & PEKindFlags.ILonly) != 0) hdr.flags |= 1; if (this.TrackDebugData) hdr.flags |= 0x10000; writer.Write(hdr.flags); writer.Write(hdr.entryPointToken); writer.Write(hdr.resources.virtualAddress); writer.Write(hdr.resources.size); writer.Write(hdr.strongNameSignature.virtualAddress); writer.Write(hdr.strongNameSignature.size); writer.Write(hdr.codeManagerTable.virtualAddress); writer.Write(hdr.codeManagerTable.size); writer.Write(hdr.vtableFixups.virtualAddress); writer.Write(hdr.vtableFixups.size); } private int WriteImportTableAndEntryPointStub(BinaryWriter/*!*/ writer, ref SectionHeader textSection) { bool use32bitAddresses = (this.peKind & PEKindFlags.Requires64bits) == 0; int pos = (int)writer.BaseStream.Position; while (pos % 4 != 0) { pos++; writer.Write((byte)0); } int ITrva = textSection.virtualAddress + pos - textSection.pointerToRawData; int ITLrva = ITrva + 40; int rvasize = 12; // size of relocation sections int hintRva = ITLrva + (use32bitAddresses ? 8 : 16); //position of name of entry point in runtime dll int nameRva = hintRva + 14; // position of name of runtime dll int ITArva = nameRva + 14 + // size of name of runtime dll 4 + // size of entry point code 0000ff25 rvasize; // size of relocation fixup this.ntHeader.addressOfEntryPoint = ITArva - rvasize - 2; this.ntHeader.importTable.virtualAddress = ITrva; this.ntHeader.importTable.size = this.ntHeader.addressOfEntryPoint - ITrva - 2; this.ntHeader.importAddressTable.virtualAddress = ITArva; this.ntHeader.importAddressTable.size = 8; //Import table writer.Write((int)ITLrva); writer.Write((int)0); writer.Write((int)0); writer.Write((int)nameRva); writer.Write((int)ITArva); writer.BaseStream.Position += 20; //Import Lookup table if (use32bitAddresses) { writer.Write((int)hintRva); writer.Write((int)0); } else { writer.Write((long)hintRva); writer.Write((long)0); } //Hint table writer.Write((short)0); //Hint string entryPointName = this.moduleKind == ModuleKindFlags.DynamicallyLinkedLibrary ? "_CorDllMain" : "_CorExeMain"; foreach (char ch in entryPointName.ToCharArray()) writer.Write((byte)ch); writer.Write((byte)0); //name of CLR runtime dll foreach (char ch in "mscoree.dll".ToCharArray()) writer.Write((byte)ch); writer.Write((byte)0); writer.Write((short)0); //entry point code, consisting of a jump indirect to _CorXXXMain writer.Write((short)0); //padding so that address to replace is on a word boundary writer.Write((byte)0xff); writer.Write((byte)0x25); writer.Write((int)ITArva + (int)this.ntHeader.imageBase); //REVIEW: is this OK for 64 bit? writer.Write((int)0); // relocation fixup must be 12 bytes. writer.Write((int)0); //Import Address Table if (use32bitAddresses) { writer.Write((int)hintRva); writer.Write((int)0); } else { writer.Write((long)hintRva); writer.Write((long)0); } //Return RVA of the target address of the indirect jump at the entry point return ITArva - rvasize; } private void WriteReference(BinaryWriter/*!*/ writer, int index, int refSize) { if (refSize == 2) writer.Write((short)index); else writer.Write(index); } } #endif }