public void Serialize(BlobBuilder writer) { switch (this.Discriminator) { case ConstantValueTypeDiscriminator.Boolean: writer.WriteBoolean(this.BooleanValue); break; case ConstantValueTypeDiscriminator.SByte: writer.WriteSByte(this.SByteValue); break; case ConstantValueTypeDiscriminator.Byte: writer.WriteByte(this.ByteValue); break; case ConstantValueTypeDiscriminator.Char: case ConstantValueTypeDiscriminator.Int16: writer.WriteInt16(this.Int16Value); break; case ConstantValueTypeDiscriminator.UInt16: writer.WriteUInt16(this.UInt16Value); break; case ConstantValueTypeDiscriminator.Single: writer.WriteSingle(this.SingleValue); break; case ConstantValueTypeDiscriminator.Int32: writer.WriteInt32(this.Int32Value); break; case ConstantValueTypeDiscriminator.UInt32: writer.WriteUInt32(this.UInt32Value); break; case ConstantValueTypeDiscriminator.Double: writer.WriteDouble(this.DoubleValue); break; case ConstantValueTypeDiscriminator.Int64: writer.WriteInt64(this.Int64Value); break; case ConstantValueTypeDiscriminator.UInt64: writer.WriteUInt64(this.UInt64Value); break; default: throw ExceptionUtilities.UnexpectedValue(this.Discriminator); } }
private void SerializeStateMachineLocalScopes(IMethodBody methodBody, MethodDefinitionHandle method) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } var writer = new BlobBuilder(); foreach (var scope in scopes) { writer.WriteUInt32((uint)scope.StartOffset); writer.WriteUInt32((uint)scope.Length); } _debugMetadataOpt.AddCustomDebugInformation( parent: method, kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.StateMachineHoistedLocalScopes), value: _debugMetadataOpt.GetOrAddBlob(writer)); }
private static unsafe void WritePESignature(BlobBuilder builder) { // MS-DOS stub (128 bytes) ReadOnlySpan <byte> header = DosHeader; Debug.Assert(DosHeader.Length == DosHeaderSize); fixed(byte *ptr = header) { builder.WriteBytes(ptr, header.Length); } // PE Signature "PE\0\0" builder.WriteUInt32(PEHeaders.PESignature); }
/// <summary> /// Serialized #Pdb stream. /// </summary> protected override void SerializeStandalonePdbStream(BlobBuilder builder) { int startPosition = builder.Position; // the id will be filled in later _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize); builder.WriteUInt32((uint)_entryPointToken); builder.WriteUInt64(MetadataSizes.ExternalTablesMask); MetadataWriterUtilities.SerializeRowCounts(builder, MetadataSizes.ExternalRowCounts); int endPosition = builder.Position; Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition); }
private static BlobHandle SerializeAsyncMethodSteppingInfo(MetadataBuilder metadataBuilder, ISymUnmanagedAsyncMethod symAsyncMethod, int moveNextMethodRowId) { var builder = new BlobBuilder(); builder.WriteUInt32((uint)((long)symAsyncMethod.GetCatchHandlerILOffset() + 1)); foreach (var stepInfo in symAsyncMethod.GetAsyncStepInfos()) { builder.WriteInt32(stepInfo.YieldOffset); builder.WriteInt32(stepInfo.ResumeOffset); builder.WriteCompressedInteger(moveNextMethodRowId); } return(metadataBuilder.GetOrAddBlob(builder)); }
public void WritePrimitive() { var writer = new BlobBuilder(17); writer.WriteUInt32(0x11223344); writer.WriteUInt16(0x5566); writer.WriteByte(0x77); writer.WriteUInt64(0x8899aabbccddeeff); writer.WriteInt32(-1); writer.WriteInt16(-2); writer.WriteSByte(-3); writer.WriteBoolean(true); writer.WriteBoolean(false); writer.WriteInt64(unchecked ((long)0xfedcba0987654321)); writer.WriteDateTime(new DateTime(0x1112223334445556)); writer.WriteDecimal(102030405060.70m); writer.WriteDouble(double.NaN); writer.WriteSingle(float.NegativeInfinity); var guid = new Guid("01020304-0506-0708-090A-0B0C0D0E0F10"); writer.WriteBytes(guid.ToByteArray()); writer.WriteGuid(guid); AssertEx.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x77, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0x00, 0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE, 0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11, 0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }, writer.ToArray()); }
/// <summary> /// Helper method to serialize CorHeader into a BlobBuilder. /// </summary> /// <param name="builder">Target blob builder to receive the serialized data</param> public void WriteTo(BlobBuilder builder) { builder.WriteInt32(CorHeaderSize); builder.WriteUInt16(MajorRuntimeVersion); builder.WriteUInt16(MinorRuntimeVersion); WriteDirectoryEntry(MetadataDirectory, builder); builder.WriteUInt32((uint)Flags); builder.WriteInt32(EntryPointTokenOrRelativeVirtualAddress); WriteDirectoryEntry(ResourcesDirectory, builder); WriteDirectoryEntry(StrongNameSignatureDirectory, builder); WriteDirectoryEntry(CodeManagerTableDirectory, builder); WriteDirectoryEntry(VtableFixupsDirectory, builder); WriteDirectoryEntry(ExportAddressTableJumpsDirectory, builder); WriteDirectoryEntry(ManagedNativeHeaderDirectory, builder); }
private void WriteImportTable(BlobBuilder builder, int importTableRva, int importAddressTableRva) { int start = builder.Count; int ilRVA = importTableRva + 40; int hintRva = ilRVA + (Is32Bit ? 12 : 16); int nameRva = hintRva + 12 + 2; // Import table builder.WriteUInt32((uint)ilRVA); // 4 builder.WriteUInt32(0); // 8 builder.WriteUInt32(0); // 12 builder.WriteUInt32((uint)nameRva); // 16 builder.WriteUInt32((uint)importAddressTableRva); // 20 builder.WriteBytes(0, 20); // 40 // Import Lookup table if (Is32Bit) { builder.WriteUInt32((uint)hintRva); // 44 builder.WriteUInt32(0); // 48 builder.WriteUInt32(0); // 52 } else { builder.WriteUInt64((uint)hintRva); // 48 builder.WriteUInt64(0); // 56 } // Hint table builder.WriteUInt16(0); // Hint 54|58 foreach (char ch in CorEntryPointName) { builder.WriteByte((byte)ch); // 65|69 } builder.WriteByte(0); // 66|70 Debug.Assert(builder.Count - start == SizeOfImportTable); }
private static int WriteCodeViewData(BlobBuilder builder, string pdbPath, Guid pdbGuid) { int start = builder.Count; builder.WriteByte((byte)'R'); builder.WriteByte((byte)'S'); builder.WriteByte((byte)'D'); builder.WriteByte((byte)'S'); // PDB id: builder.WriteGuid(pdbGuid); // age builder.WriteUInt32(1); // UTF-8 encoded zero-terminated path to PDB int pathStart = builder.Count; builder.WriteUTF8(pdbPath, allowUnpairedSurrogates: true); builder.WriteByte(0); return(builder.Count - start); }
/// <summary> /// Write one entry in the "Debug Directory (Image Only)" /// See https://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx /// section 5.1.1 (pages 71-72). /// </summary> private static void WriteDebugTableEntry( BlobBuilder writer, byte[] stamp, uint version, // major and minor version, combined uint debugType, uint sizeOfData, uint addressOfRawData, uint pointerToRawData) { writer.WriteUInt32(0); // characteristics Debug.Assert(stamp.Length == 4); writer.WriteBytes(stamp); writer.WriteUInt32(version); writer.WriteUInt32(debugType); writer.WriteUInt32(sizeOfData); writer.WriteUInt32(addressOfRawData); writer.WriteUInt32(pointerToRawData); }
public void ToImmutableArray() { var builder = new BlobBuilder(16); AssertEx.Equal(new byte[] { }, builder.ToArray(0, 0)); for (int i = 0; i < 13; i++) { builder.WriteByte((byte)i); } builder.WriteUInt32(0xaabbccdd); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xDD, 0xCC, 0xBB, 0xAA }, builder.ToImmutableArray()); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(0, 0)); AssertEx.Equal(new byte[] { 0 }, builder.ToImmutableArray(0, 1)); AssertEx.Equal(new byte[] { 1 }, builder.ToImmutableArray(1, 1)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(14, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(15, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(16, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(17, 0)); AssertEx.Equal(new byte[] { 0xdd }, builder.ToImmutableArray(13, 1)); AssertEx.Equal(new byte[] { 0xcc }, builder.ToImmutableArray(14, 1)); AssertEx.Equal(new byte[] { 0xbb }, builder.ToImmutableArray(15, 1)); AssertEx.Equal(new byte[] { 0xaa }, builder.ToImmutableArray(16, 1)); AssertEx.Equal(new byte[] { 0xdd, 0xcc }, builder.ToImmutableArray(13, 2)); AssertEx.Equal(new byte[] { 0xcc, 0xbb }, builder.ToImmutableArray(14, 2)); AssertEx.Equal(new byte[] { 0xbb, 0xaa }, builder.ToImmutableArray(15, 2)); AssertEx.Equal(new byte[] { 0xdd, 0xcc, 0xbb }, builder.ToImmutableArray(13, 3)); AssertEx.Equal(new byte[] { 0xcc, 0xbb, 0xaa }, builder.ToImmutableArray(14, 3)); AssertEx.Equal(new byte[] { 0xdd, 0xcc, 0xbb, 0xaa }, builder.ToImmutableArray(13, 4)); }
private static void WriteSectionHeader(BlobBuilder builder, SerializedSection serializedSection) { if (serializedSection.VirtualSize == 0) { return; } for (int j = 0, m = serializedSection.Name.Length; j < 8; j++) { if (j < m) { builder.WriteByte((byte)serializedSection.Name[j]); } else { builder.WriteByte(0); } } builder.WriteUInt32((uint)serializedSection.VirtualSize); builder.WriteUInt32((uint)serializedSection.RelativeVirtualAddress); builder.WriteUInt32((uint)serializedSection.SizeOfRawData); builder.WriteUInt32((uint)serializedSection.PointerToRawData); // PointerToRelocations (TODO: not supported): builder.WriteUInt32(0); // PointerToLinenumbers (TODO: not supported): builder.WriteUInt32(0); // NumberOfRelocations (TODO: not supported): builder.WriteUInt16(0); // NumberOfLinenumbers (TODO: not supported): builder.WriteUInt16(0); builder.WriteUInt32((uint)serializedSection.Characteristics); }
private void WriteImportAddressTable(Stream peStream, int importTableRva) { var writer = new BlobBuilder(SizeOfImportAddressTable); int ilRVA = importTableRva + 40; int hintRva = ilRVA + (_is32bit ? 12 : 16); // Import Address Table if (_is32bit) { writer.WriteUInt32((uint)hintRva); // 4 writer.WriteUInt32(0); // 8 } else { writer.WriteUInt64((uint)hintRva); // 8 writer.WriteUInt64(0); // 16 } Debug.Assert(writer.Count == SizeOfImportAddressTable); writer.WriteContentTo(peStream); }
private void SerializeExportedTypeTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (ExportedTypeRow exportedType in _exportedTypeTable) { writer.WriteUInt32((uint)exportedType.Flags); writer.WriteUInt32(exportedType.TypeDefId); writer.WriteReference((uint)GetHeapOffset(exportedType.TypeName), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(exportedType.TypeNamespace), metadataSizes.StringIndexSize); writer.WriteReference(exportedType.Implementation, metadataSizes.ImplementationCodedIndexSize); } }
internal static void WriteConstant(BlobBuilder writer, object value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit. writer.WriteUInt32(0); return; } var type = value.GetType(); if (type.GetTypeInfo().IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { writer.WriteBoolean((bool)value); } else if (type == typeof(int)) { writer.WriteInt32((int)value); } else if (type == typeof(string)) { writer.WriteUTF16((string)value); } else if (type == typeof(byte)) { writer.WriteByte((byte)value); } else if (type == typeof(char)) { writer.WriteUInt16((char)value); } else if (type == typeof(double)) { writer.WriteDouble((double)value); } else if (type == typeof(short)) { writer.WriteInt16((short)value); } else if (type == typeof(long)) { writer.WriteInt64((long)value); } else if (type == typeof(sbyte)) { writer.WriteSByte((sbyte)value); } else if (type == typeof(float)) { writer.WriteSingle((float)value); } else if (type == typeof(ushort)) { writer.WriteUInt16((ushort)value); } else if (type == typeof(uint)) { writer.WriteUInt32((uint)value); } else if (type == typeof(ulong)) { writer.WriteUInt64((ulong)value); } else { // TODO: message throw new ArgumentException(); } }
private void WritePEHeader(BlobBuilder builder, PEDirectoriesBuilder directories, ImmutableArray <SerializedSection> sections) { builder.WriteUInt16((ushort)(Header.Is32Bit ? PEMagic.PE32 : PEMagic.PE32Plus)); builder.WriteByte(Header.MajorLinkerVersion); builder.WriteByte(Header.MinorLinkerVersion); // SizeOfCode: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsCode)); // SizeOfInitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsInitializedData)); // SizeOfUninitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsUninitializedData)); // AddressOfEntryPoint: builder.WriteUInt32((uint)directories.AddressOfEntryPoint); // BaseOfCode: int codeSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsCode); builder.WriteUInt32((uint)(codeSectionIndex != -1 ? sections[codeSectionIndex].RelativeVirtualAddress : 0)); if (Header.Is32Bit) { // BaseOfData: int dataSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsInitializedData); builder.WriteUInt32((uint)(dataSectionIndex != -1 ? sections[dataSectionIndex].RelativeVirtualAddress : 0)); builder.WriteUInt32((uint)Header.ImageBase); } else { builder.WriteUInt64(Header.ImageBase); } // NT additional fields: builder.WriteUInt32((uint)Header.SectionAlignment); builder.WriteUInt32((uint)Header.FileAlignment); builder.WriteUInt16(Header.MajorOperatingSystemVersion); builder.WriteUInt16(Header.MinorOperatingSystemVersion); builder.WriteUInt16(Header.MajorImageVersion); builder.WriteUInt16(Header.MinorImageVersion); builder.WriteUInt16(Header.MajorSubsystemVersion); builder.WriteUInt16(Header.MinorSubsystemVersion); // Win32VersionValue (reserved, should be 0) builder.WriteUInt32(0); // SizeOfImage: var lastSection = sections[sections.Length - 1]; builder.WriteUInt32((uint)BitArithmetic.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, Header.SectionAlignment)); // SizeOfHeaders: builder.WriteUInt32((uint)BitArithmetic.Align(Header.ComputeSizeOfPEHeaders(sections.Length), Header.FileAlignment)); // Checksum: // Shall be zero for strong name signing. _lazyChecksum = builder.ReserveBytes(sizeof(uint)); new BlobWriter(_lazyChecksum).WriteUInt32(0); builder.WriteUInt16((ushort)Header.Subsystem); builder.WriteUInt16((ushort)Header.DllCharacteristics); if (Header.Is32Bit) { builder.WriteUInt32((uint)Header.SizeOfStackReserve); builder.WriteUInt32((uint)Header.SizeOfStackCommit); builder.WriteUInt32((uint)Header.SizeOfHeapReserve); builder.WriteUInt32((uint)Header.SizeOfHeapCommit); } else { builder.WriteUInt64(Header.SizeOfStackReserve); builder.WriteUInt64(Header.SizeOfStackCommit); builder.WriteUInt64(Header.SizeOfHeapReserve); builder.WriteUInt64(Header.SizeOfHeapCommit); } // LoaderFlags builder.WriteUInt32(0); // The number of data-directory entries in the remainder of the header. builder.WriteUInt32(16); // directory entries: builder.WriteUInt32((uint)directories.ExportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ExportTable.Size); builder.WriteUInt32((uint)directories.ImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ImportTable.Size); builder.WriteUInt32((uint)directories.ResourceTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ResourceTable.Size); builder.WriteUInt32((uint)directories.ExceptionTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ExceptionTable.Size); // Authenticode CertificateTable directory. Shall be zero before the PE is signed. builder.WriteUInt32(0); builder.WriteUInt32(0); builder.WriteUInt32((uint)directories.BaseRelocationTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.BaseRelocationTable.Size); builder.WriteUInt32((uint)directories.DebugTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.DebugTable.Size); builder.WriteUInt32((uint)directories.CopyrightTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.CopyrightTable.Size); builder.WriteUInt32((uint)directories.GlobalPointerTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.GlobalPointerTable.Size); builder.WriteUInt32((uint)directories.ThreadLocalStorageTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ThreadLocalStorageTable.Size); builder.WriteUInt32((uint)directories.LoadConfigTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.LoadConfigTable.Size); builder.WriteUInt32((uint)directories.BoundImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.BoundImportTable.Size); builder.WriteUInt32((uint)directories.ImportAddressTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ImportAddressTable.Size); builder.WriteUInt32((uint)directories.DelayImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.DelayImportTable.Size); builder.WriteUInt32((uint)directories.CorHeaderTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.CorHeaderTable.Size); // Reserved, should be 0 builder.WriteUInt64(0); }
private void WritePEHeader(BlobBuilder builder, PEDirectoriesBuilder headers, ImmutableArray <SerializedSection> sections) { builder.WriteUInt16((ushort)(Is32Bit ? PEMagic.PE32 : PEMagic.PE32Plus)); builder.WriteByte(MajorLinkerVersion); builder.WriteByte(MinorLinkerVersion); // SizeOfCode: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsCode)); // SizeOfInitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsInitializedData)); // SizeOfUninitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsUninitializedData)); // AddressOfEntryPoint: builder.WriteUInt32((uint)headers.AddressOfEntryPoint); // BaseOfCode: int codeSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsCode); builder.WriteUInt32((uint)(codeSectionIndex != -1 ? sections[codeSectionIndex].RelativeVirtualAddress : 0)); if (Is32Bit) { // BaseOfData: int dataSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsInitializedData); builder.WriteUInt32((uint)(dataSectionIndex != -1 ? sections[dataSectionIndex].RelativeVirtualAddress : 0)); builder.WriteUInt32((uint)ImageBase); } else { builder.WriteUInt64(ImageBase); } // NT additional fields: builder.WriteUInt32((uint)SectionAlignment); builder.WriteUInt32((uint)FileAlignment); builder.WriteUInt16(MajorOperatingSystemVersion); builder.WriteUInt16(MinorOperatingSystemVersion); builder.WriteUInt16(MajorImageVersion); builder.WriteUInt16(MinorImageVersion); builder.WriteUInt16(MajorSubsystemVersion); builder.WriteUInt16(MinorSubsystemVersion); // Win32VersionValue (reserved, should be 0) builder.WriteUInt32(0); // SizeOfImage: var lastSection = sections[sections.Length - 1]; builder.WriteUInt32((uint)BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, SectionAlignment)); // SizeOfHeaders: builder.WriteUInt32((uint)BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sections.Length, Is32Bit), FileAlignment)); // Checksum (TODO: not supported): builder.WriteUInt32(0); builder.WriteUInt16((ushort)Subsystem); builder.WriteUInt16((ushort)DllCharacteristics); if (Is32Bit) { builder.WriteUInt32((uint)SizeOfStackReserve); builder.WriteUInt32((uint)SizeOfStackCommit); builder.WriteUInt32((uint)SizeOfHeapReserve); builder.WriteUInt32((uint)SizeOfHeapCommit); } else { builder.WriteUInt64(SizeOfStackReserve); builder.WriteUInt64(SizeOfStackCommit); builder.WriteUInt64(SizeOfHeapReserve); builder.WriteUInt64(SizeOfHeapCommit); } // LoaderFlags builder.WriteUInt32(0); // The number of data-directory entries in the remainder of the header. builder.WriteUInt32(16); // directory entries: builder.WriteUInt32((uint)headers.ExportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ExportTable.Size); builder.WriteUInt32((uint)headers.ImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ImportTable.Size); builder.WriteUInt32((uint)headers.ResourceTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ResourceTable.Size); builder.WriteUInt32((uint)headers.ExceptionTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ExceptionTable.Size); builder.WriteUInt32((uint)headers.CertificateTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CertificateTable.Size); builder.WriteUInt32((uint)headers.BaseRelocationTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.BaseRelocationTable.Size); builder.WriteUInt32((uint)headers.DebugTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.DebugTable.Size); builder.WriteUInt32((uint)headers.CopyrightTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CopyrightTable.Size); builder.WriteUInt32((uint)headers.GlobalPointerTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.GlobalPointerTable.Size); builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.Size); builder.WriteUInt32((uint)headers.LoadConfigTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.LoadConfigTable.Size); builder.WriteUInt32((uint)headers.BoundImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.BoundImportTable.Size); builder.WriteUInt32((uint)headers.ImportAddressTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ImportAddressTable.Size); builder.WriteUInt32((uint)headers.DelayImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.DelayImportTable.Size); builder.WriteUInt32((uint)headers.CorHeaderTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CorHeaderTable.Size); // Reserved, should be 0 builder.WriteUInt64(0); }
private static void WriteSectionHeader(BlobBuilder builder, Section section, SerializedSection serializedSection) { if (serializedSection.VirtualSize == 0) { return; } for (int j = 0, m = section.Name.Length; j < 8; j++) { if (j < m) { builder.WriteByte((byte)section.Name[j]); } else { builder.WriteByte(0); } } builder.WriteUInt32((uint)serializedSection.VirtualSize); builder.WriteUInt32((uint)serializedSection.RelativeVirtualAddress); builder.WriteUInt32((uint)serializedSection.SizeOfRawData); builder.WriteUInt32((uint)serializedSection.PointerToRawData); // PointerToRelocations (TODO: not supported): builder.WriteUInt32(0); // PointerToLinenumbers (TODO: not supported): builder.WriteUInt32(0); // NumberOfRelocations (TODO: not supported): builder.WriteUInt16(0); // NumberOfLinenumbers (TODO: not supported): builder.WriteUInt16(0); builder.WriteUInt32((uint)section.Characteristics); }
private void SerializeAssemblyRefTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (AssemblyRefTableRow row in _assemblyRefTable) { writer.WriteUInt16((ushort)row.Version.Major); writer.WriteUInt16((ushort)row.Version.Minor); writer.WriteUInt16((ushort)row.Version.Build); writer.WriteUInt16((ushort)row.Version.Revision); writer.WriteUInt32(row.Flags); writer.WriteReference((uint)GetHeapOffset(row.PublicKeyToken), metadataSizes.BlobIndexSize); writer.WriteReference((uint)GetHeapOffset(row.Name), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(row.Culture), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(row.HashValue), metadataSizes.BlobIndexSize); } }
public void WritePrimitive() { var writer = new BlobBuilder(17); writer.WriteUInt32(0x11223344); writer.WriteUInt16(0x5566); writer.WriteByte(0x77); writer.WriteUInt64(0x8899aabbccddeeff); writer.WriteInt32(-1); writer.WriteInt16(-2); writer.WriteSByte(-3); writer.WriteBoolean(true); writer.WriteBoolean(false); writer.WriteInt64(unchecked((long)0xfedcba0987654321)); writer.WriteDateTime(new DateTime(0x1112223334445556)); writer.WriteDecimal(102030405060.70m); writer.WriteDouble(double.NaN); writer.WriteSingle(float.NegativeInfinity); var guid = new Guid("01020304-0506-0708-090A-0B0C0D0E0F10"); writer.WriteBytes(guid.ToByteArray()); writer.WriteGuid(guid); AssertEx.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x77, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0x00, 0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE, 0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11, 0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }, writer.ToArray()); }
private void SerializeClassLayoutTable(BlobBuilder writer, MetadataSizes metadataSizes) { #if DEBUG for (int i = 1; i < _classLayoutTable.Count; i++) { Debug.Assert(_classLayoutTable[i - 1].Parent < _classLayoutTable[i].Parent); } #endif foreach (ClassLayoutRow classLayout in _classLayoutTable) { writer.WriteUInt16(classLayout.PackingSize); writer.WriteUInt32(classLayout.ClassSize); writer.WriteReference(classLayout.Parent, metadataSizes.TypeDefIndexSize); } }
private void SerializeLocalScopeTable(BlobBuilder writer, MetadataSizes metadataSizes) { #if DEBUG // Spec: The table is required to be sorted first by Method in ascending order, then by StartOffset in ascending order, then by Length in descending order. for (int i = 1; i < _localScopeTable.Count; i++) { Debug.Assert(_localScopeTable[i - 1].Method <= _localScopeTable[i].Method); if (_localScopeTable[i - 1].Method == _localScopeTable[i].Method) { Debug.Assert(_localScopeTable[i - 1].StartOffset <= _localScopeTable[i].StartOffset); if (_localScopeTable[i - 1].StartOffset == _localScopeTable[i].StartOffset) { Debug.Assert(_localScopeTable[i - 1].Length >= _localScopeTable[i].Length); } } } #endif foreach (var row in _localScopeTable) { writer.WriteReference(row.Method, metadataSizes.MethodDefIndexSize); writer.WriteReference(row.ImportScope, metadataSizes.ImportScopeIndexSize); writer.WriteReference(row.VariableList, metadataSizes.LocalVariableIndexSize); writer.WriteReference(row.ConstantList, metadataSizes.LocalConstantIndexSize); writer.WriteUInt32(row.StartOffset); writer.WriteUInt32(row.Length); } }
private void SerializeManifestResourceTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (ManifestResourceRow manifestResource in _manifestResourceTable) { writer.WriteUInt32(manifestResource.Offset); writer.WriteUInt32(manifestResource.Flags); writer.WriteReference((uint)GetHeapOffset(manifestResource.Name), metadataSizes.StringIndexSize); writer.WriteReference(manifestResource.Implementation, metadataSizes.ImplementationCodedIndexSize); } }
private static void WriteCorHeader(Stream peStream, CorHeader corHeader) { var writer = new BlobBuilder(CorHeaderSize); writer.WriteUInt32(CorHeaderSize); writer.WriteUInt16(corHeader.MajorRuntimeVersion); writer.WriteUInt16(corHeader.MinorRuntimeVersion); writer.WriteUInt32((uint)corHeader.MetadataDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.MetadataDirectory.Size); writer.WriteUInt32((uint)corHeader.Flags); writer.WriteUInt32((uint)corHeader.EntryPointTokenOrRelativeVirtualAddress); writer.WriteUInt32((uint)(corHeader.ResourcesDirectory.Size == 0 ? 0 : corHeader.ResourcesDirectory.RelativeVirtualAddress)); // 28 writer.WriteUInt32((uint)corHeader.ResourcesDirectory.Size); writer.WriteUInt32((uint)(corHeader.StrongNameSignatureDirectory.Size == 0 ? 0 : corHeader.StrongNameSignatureDirectory.RelativeVirtualAddress)); // 36 writer.WriteUInt32((uint)corHeader.StrongNameSignatureDirectory.Size); writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.Size); writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.Size); writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.Size); writer.WriteUInt64(0); Debug.Assert(writer.Count == CorHeaderSize); Debug.Assert(writer.Count % 4 == 0); writer.WriteContentTo(peStream); }
private void WriteRelocSection(Stream peStream, SectionHeader relocSection, int entryPointAddress) { peStream.Position = relocSection.PointerToRawData; var writer = new BlobBuilder(relocSection.SizeOfRawData); writer.WriteUInt32((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); writer.WriteUInt32(_properties.Requires64bits && !_properties.RequiresAmdInstructionSet ? 14u : 12u); uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; uint relocType = _properties.Requires64bits ? 10u : 3u; ushort s = (ushort)((relocType << 12) | offsetWithinPage); writer.WriteUInt16(s); if (_properties.Requires64bits && !_properties.RequiresAmdInstructionSet) { writer.WriteUInt32(relocType << 12); } writer.WriteUInt16(0); // next chunk's RVA writer.PadTo(relocSection.SizeOfRawData); writer.WriteContentTo(peStream); }
private void WriteImportAddressTable(BlobBuilder builder, int importTableRva) { int start = builder.Count; int ilRva = importTableRva + 40; int hintRva = ilRva + (Is32Bit ? 12 : 16); // Import Address Table if (Is32Bit) { builder.WriteUInt32((uint)hintRva); // 4 builder.WriteUInt32(0); // 8 } else { builder.WriteUInt64((uint)hintRva); // 8 builder.WriteUInt64(0); // 16 } Debug.Assert(builder.Count - start == SizeOfImportAddressTable); }
private void SerializeFieldRvaTable(BlobBuilder writer, MetadataSizes metadataSizes, int mappedFieldDataStreamRva) { #if DEBUG for (int i = 1; i < _fieldRvaTable.Count; i++) { Debug.Assert(_fieldRvaTable[i - 1].Field < _fieldRvaTable[i].Field); } #endif foreach (FieldRvaRow fieldRva in _fieldRvaTable) { writer.WriteUInt32((uint)mappedFieldDataStreamRva + fieldRva.Offset); writer.WriteReference(fieldRva.Field, metadataSizes.FieldDefIndexSize); } }
private void SerializeTypeDefTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (TypeDefRow typeDef in _typeDefTable) { writer.WriteUInt32(typeDef.Flags); writer.WriteReference((uint)GetHeapOffset(typeDef.Name), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(typeDef.Namespace), metadataSizes.StringIndexSize); writer.WriteReference(typeDef.Extends, metadataSizes.TypeDefOrRefCodedIndexSize); writer.WriteReference(typeDef.FieldList, metadataSizes.FieldDefIndexSize); writer.WriteReference(typeDef.MethodList, metadataSizes.MethodDefIndexSize); } }
private void WriteCorHeader(BlobBuilder builder, int textSectionRva, int entryPointTokenOrRva, CorFlags corFlags) { const ushort majorRuntimeVersion = 2; const ushort minorRuntimeVersion = 5; int metadataRva = textSectionRva + ComputeOffsetToMetadata(); int resourcesRva = metadataRva + MetadataSize; int signatureRva = resourcesRva + ResourceDataSize; int start = builder.Count; // Size: builder.WriteUInt32(CorHeaderSize); // Version: builder.WriteUInt16(majorRuntimeVersion); builder.WriteUInt16(minorRuntimeVersion); // MetadataDirectory: builder.WriteUInt32((uint)metadataRva); builder.WriteUInt32((uint)MetadataSize); // COR Flags: builder.WriteUInt32((uint)corFlags); // EntryPoint: builder.WriteUInt32((uint)entryPointTokenOrRva); // ResourcesDirectory: builder.WriteUInt32((uint)(ResourceDataSize == 0 ? 0 : resourcesRva)); // 28 builder.WriteUInt32((uint)ResourceDataSize); // StrongNameSignatureDirectory: builder.WriteUInt32((uint)(StrongNameSignatureSize == 0 ? 0 : signatureRva)); // 36 builder.WriteUInt32((uint)StrongNameSignatureSize); // CodeManagerTableDirectory (not supported): builder.WriteUInt32(0); builder.WriteUInt32(0); // VtableFixupsDirectory (not supported): builder.WriteUInt32(0); builder.WriteUInt32(0); // ExportAddressTableJumpsDirectory (not supported): builder.WriteUInt32(0); builder.WriteUInt32(0); // ManagedNativeHeaderDirectory (not supported): builder.WriteUInt32(0); builder.WriteUInt32(0); Debug.Assert(builder.Count - start == CorHeaderSize); Debug.Assert(builder.Count % 4 == 0); }
private static void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) { writer.WriteUInt32(0); // Characteristics writer.WriteUInt32(0); // Timestamp writer.WriteUInt32(0); // Version writer.WriteUInt16(directory.NumberOfNamedEntries); writer.WriteUInt16(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id; string name; uint nameOffset = (uint)dataWriter.Count + sizeOfDirectoryTree; uint directoryOffset = k; Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { id = subDir.ID; name = subDir.Name; if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } else { //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed //immediately by the data that it refers to. This results //in a layout different than that produced by pulling the resources //from an OBJ. In that case all of the data bits of a resource are //contiguous in .rsrc$02. After processing these will end up at //the end of .rsrc following all of the directory //info and IMAGE_RESOURCE_DATA_ENTRYs IWin32Resource r = (IWin32Resource)directory.Entries[i]; id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Count)); byte[] data = new List <byte>(r.Data).ToArray(); dataWriter.WriteUInt32((uint)data.Length); dataWriter.WriteUInt32(r.CodePage); dataWriter.WriteUInt32(0); dataWriter.WriteBytes(data); while ((dataWriter.Count % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt32(id); } else { if (name == null) { name = string.Empty; } writer.WriteUInt32(nameOffset | 0x80000000); dataWriter.WriteUInt16((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUInt32(directoryOffset | 0x80000000); } else { writer.WriteUInt32(nameOffset); } } k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } } }
private readonly static byte[] zeroStamp = new byte[4]; // four bytes of zero /// <summary> /// Write the entire "Debug Directory (Image Only)" along with data that it points to. /// </summary> internal void WriteDebugTable(BlobBuilder builder, PESectionLocation textSectionLocation, ContentId nativePdbContentId, ContentId portablePdbContentId) { Debug.Assert(builder.Count == 0); int tableSize = ImageDebugDirectoryBaseSize; Debug.Assert(tableSize != 0); Debug.Assert(nativePdbContentId.IsDefault || portablePdbContentId.IsDefault); Debug.Assert(!EmitPdb || (nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault)); int dataSize = ComputeSizeOfDebugDirectoryData(); if (EmitPdb) { const int IMAGE_DEBUG_TYPE_CODEVIEW = 2; // from PE spec uint dataOffset = (uint)(ComputeOffsetToDebugTable() + tableSize); WriteDebugTableEntry(builder, stamp: nativePdbContentId.Stamp ?? portablePdbContentId.Stamp, version: portablePdbContentId.IsDefault ? (uint)0 : ('P' << 24 | 'M' << 16 | 0x01 << 8 | 0x00), debugType: IMAGE_DEBUG_TYPE_CODEVIEW, sizeOfData: (uint)dataSize, addressOfRawData: (uint)textSectionLocation.RelativeVirtualAddress + dataOffset, // RVA of the data pointerToRawData: (uint)textSectionLocation.PointerToRawData + dataOffset); // position of the data in the PE stream } if (IsDeterministic) { const int IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16; // from PE spec WriteDebugTableEntry(builder, stamp: zeroStamp, version: 0, debugType: IMAGE_DEBUG_TYPE_NO_TIMESTAMP, sizeOfData: 0, addressOfRawData: 0, pointerToRawData: 0); } // We should now have written all and precisely the data we said we'd write for the table entries. Debug.Assert(builder.Count == tableSize); // ==================== // The following is additional data beyond the debug directory at the offset `dataOffset` // pointed to by the ImageDebugTypeCodeView entry. if (EmitPdb) { builder.WriteByte((byte)'R'); builder.WriteByte((byte)'S'); builder.WriteByte((byte)'D'); builder.WriteByte((byte)'S'); // PDB id: builder.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid); // age builder.WriteUInt32(1); // TODO: allow specify for native PDBs // UTF-8 encoded zero-terminated path to PDB int pathStart = builder.Count; builder.WriteUTF8(PdbPathOpt, allowUnpairedSurrogates: true); builder.WriteByte(0); // padding: builder.WriteBytes(0, Math.Max(0, MinPdbPath - (builder.Count - pathStart))); } // We should now have written all and precisely the data we said we'd write for the table and its data. Debug.Assert(builder.Count == tableSize + dataSize); }
private void SerializeFileTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (FileTableRow fileReference in _fileTable) { writer.WriteUInt32(fileReference.Flags); writer.WriteReference((uint)GetHeapOffset(fileReference.FileName), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(fileReference.HashValue), metadataSizes.BlobIndexSize); } }
private void WriteRuntimeStartupStub(BlobBuilder sectionBuilder, int importAddressTableRva, ulong baseAddress) { // entry point code, consisting of a jump indirect to _CorXXXMain if (Is32Bit) { // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively to the start of the section. sectionBuilder.Align(4); sectionBuilder.WriteUInt16(0); sectionBuilder.WriteByte(0xff); sectionBuilder.WriteByte(0x25); //4 sectionBuilder.WriteUInt32((uint)importAddressTableRva + (uint)baseAddress); //8 } else { // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively to the start of the section. sectionBuilder.Align(8); sectionBuilder.WriteUInt32(0); sectionBuilder.WriteUInt16(0); sectionBuilder.WriteByte(0xff); sectionBuilder.WriteByte(0x25); //8 sectionBuilder.WriteUInt64((ulong)importAddressTableRva + baseAddress); //16 } }
private void SerializeMethodDefTable(BlobBuilder writer, MetadataSizes metadataSizes, int methodBodyStreamRva) { foreach (MethodRow method in _methodDefTable) { if (method.BodyOffset == -1) { writer.WriteUInt32(0); } else { writer.WriteUInt32((uint)(methodBodyStreamRva + method.BodyOffset)); } writer.WriteUInt16(method.ImplFlags); writer.WriteUInt16(method.Flags); writer.WriteReference((uint)GetHeapOffset(method.Name), metadataSizes.StringIndexSize); writer.WriteReference((uint)GetHeapOffset(method.Signature), metadataSizes.BlobIndexSize); writer.WriteReference(method.ParamList, metadataSizes.ParameterIndexSize); } }
private static void WriteSectionHeader(SectionHeader sectionHeader, BlobBuilder writer) { if (sectionHeader.VirtualSize == 0) { return; } for (int j = 0, m = sectionHeader.Name.Length; j < 8; j++) { if (j < m) { writer.WriteByte((byte)sectionHeader.Name[j]); } else { writer.WriteByte(0); } } writer.WriteUInt32((uint)sectionHeader.VirtualSize); writer.WriteUInt32((uint)sectionHeader.RelativeVirtualAddress); writer.WriteUInt32((uint)sectionHeader.SizeOfRawData); writer.WriteUInt32((uint)sectionHeader.PointerToRawData); writer.WriteUInt32((uint)sectionHeader.PointerToRelocations); writer.WriteUInt32((uint)sectionHeader.PointerToLinenumbers); writer.WriteUInt16(sectionHeader.NumberOfRelocations); writer.WriteUInt16(sectionHeader.NumberOfLinenumbers); writer.WriteUInt32((uint)sectionHeader.Characteristics); }
private void SerializeMetadataHeader(BlobBuilder builder) { int startOffset = builder.Count; // signature builder.WriteUInt32(0x424A5342); // major version builder.WriteUInt16(1); // minor version builder.WriteUInt16(1); // reserved builder.WriteUInt32(0); // metadata version length builder.WriteUInt32(MetadataSizes.MetadataVersionPaddedLength); int n = Math.Min(MetadataSizes.MetadataVersionPaddedLength, _metadataVersion.Length); for (int i = 0; i < n; i++) { builder.WriteByte((byte)_metadataVersion[i]); } for (int i = n; i < MetadataSizes.MetadataVersionPaddedLength; i++) { builder.WriteByte(0); } // reserved builder.WriteUInt16(0); // number of streams builder.WriteUInt16((ushort)(5 + (_sizes.IsMinimalDelta ? 1 : 0) + (_sizes.IsStandaloneDebugMetadata ? 1 : 0))); // stream headers int offsetFromStartOfMetadata = _sizes.MetadataHeaderSize; // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID if (_sizes.IsStandaloneDebugMetadata) { SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.StandalonePdbStreamSize, "#Pdb", builder); } // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables; // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard. // // Note: EnC delta is stored as uncompressed metadata stream. SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.MetadataTableStreamSize, (_sizes.IsMetadataTableStreamCompressed ? "#~" : "#-"), builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder); if (_sizes.IsMinimalDelta) { SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder); } int endOffset = builder.Count; Debug.Assert(endOffset - startOffset == _sizes.MetadataHeaderSize); }
private void WriteImportTable(Stream peStream, int importTableRva, int importAddressTableRva) { var writer = new BlobBuilder(SizeOfImportTable); int ilRVA = importTableRva + 40; int hintRva = ilRVA + (_is32bit ? 12 : 16); int nameRva = hintRva + 12 + 2; // Import table writer.WriteUInt32((uint)ilRVA); // 4 writer.WriteUInt32(0); // 8 writer.WriteUInt32(0); // 12 writer.WriteUInt32((uint)nameRva); // 16 writer.WriteUInt32((uint)importAddressTableRva); // 20 writer.WriteBytes(0, 20); // 40 // Import Lookup table if (_is32bit) { writer.WriteUInt32((uint)hintRva); // 44 writer.WriteUInt32(0); // 48 writer.WriteUInt32(0); // 52 } else { writer.WriteUInt64((uint)hintRva); // 48 writer.WriteUInt64(0); // 56 } // Hint table writer.WriteUInt16(0); // Hint 54|58 foreach (char ch in CorEntryPointName) { writer.WriteByte((byte)ch); // 65|69 } writer.WriteByte(0); // 66|70 Debug.Assert(writer.Count == SizeOfImportTable); writer.WriteContentTo(peStream); }
private void WritePESignature(BlobBuilder builder) { // MS-DOS stub (128 bytes) builder.WriteBytes(s_dosHeader); // PE Signature "PE\0\0" builder.WriteUInt32(0x00004550); }
private void WriteRuntimeStartupStub(Stream peStream, int importAddressTableRva) { var writer = new BlobBuilder(16); // entry point code, consisting of a jump indirect to _CorXXXMain if (_is32bit) { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUInt16(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 writer.WriteUInt32((uint)importAddressTableRva + (uint)_properties.BaseAddress); //8 } else { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUInt32(0); writer.WriteUInt16(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //8 writer.WriteUInt64((ulong)importAddressTableRva + _properties.BaseAddress); //16 } writer.WriteContentTo(peStream); }
private void WriteCoffHeader(BlobBuilder builder, ImmutableArray<SerializedSection> sections, out Blob stampFixup) { // Machine builder.WriteUInt16((ushort)(Machine == 0 ? Machine.I386 : Machine)); // NumberOfSections builder.WriteUInt16((ushort)sections.Length); // TimeDateStamp: stampFixup = builder.ReserveBytes(sizeof(uint)); // PointerToSymbolTable (TODO: not supported): // The file pointer to the COFF symbol table, or zero if no COFF symbol table is present. // This value should be zero for a PE image. builder.WriteUInt32(0); // NumberOfSymbols (TODO: not supported): // The number of entries in the symbol table. This data can be used to locate the string table, // which immediately follows the symbol table. This value should be zero for a PE image. builder.WriteUInt32(0); // SizeOfOptionalHeader: // The size of the optional header, which is required for executable files but not for object files. // This value should be zero for an object file (TODO). builder.WriteUInt16((ushort)(Is32Bit ? 224 : 240)); // Characteristics builder.WriteUInt16((ushort)ImageCharacteristics); }
private void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) { writer.WriteUInt32(0); // Characteristics writer.WriteUInt32(0); // Timestamp writer.WriteUInt32(0); // Version writer.WriteUInt16(directory.NumberOfNamedEntries); writer.WriteUInt16(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id; string name; uint nameOffset = (uint)dataWriter.Position + sizeOfDirectoryTree; uint directoryOffset = k; Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { id = subDir.ID; name = subDir.Name; if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } else { //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed //immediately by the data that it refers to. This results //in a layout different than that produced by pulling the resources //from an OBJ. In that case all of the data bits of a resource are //contiguous in .rsrc$02. After processing these will end up at //the end of .rsrc following all of the directory //info and IMAGE_RESOURCE_DATA_ENTRYs IWin32Resource r = (IWin32Resource)directory.Entries[i]; id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position)); byte[] data = new List<byte>(r.Data).ToArray(); dataWriter.WriteUInt32((uint)data.Length); dataWriter.WriteUInt32(r.CodePage); dataWriter.WriteUInt32(0); dataWriter.WriteBytes(data); while ((dataWriter.Count % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt32(id); } else { if (name == null) { name = string.Empty; } writer.WriteUInt32(nameOffset | 0x80000000); dataWriter.WriteUInt16((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUInt32(directoryOffset | 0x80000000); } else { writer.WriteUInt32(nameOffset); } } 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, dataWriter); if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } } }
private void WritePEHeader(BlobBuilder builder, PEDirectoriesBuilder headers, ImmutableArray<SerializedSection> sections) { builder.WriteUInt16((ushort)(Is32Bit ? PEMagic.PE32 : PEMagic.PE32Plus)); builder.WriteByte(MajorLinkerVersion); builder.WriteByte(MinorLinkerVersion); // SizeOfCode: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsCode)); // SizeOfInitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsInitializedData)); // SizeOfUninitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsUninitializedData)); // AddressOfEntryPoint: builder.WriteUInt32((uint)headers.AddressOfEntryPoint); // BaseOfCode: int codeSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsCode); builder.WriteUInt32((uint)(codeSectionIndex != -1 ? sections[codeSectionIndex].RelativeVirtualAddress : 0)); if (Is32Bit) { // BaseOfData: int dataSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsInitializedData); builder.WriteUInt32((uint)(dataSectionIndex != -1 ? sections[dataSectionIndex].RelativeVirtualAddress : 0)); builder.WriteUInt32((uint)ImageBase); } else { builder.WriteUInt64(ImageBase); } // NT additional fields: builder.WriteUInt32((uint)SectionAlignment); builder.WriteUInt32((uint)FileAlignment); builder.WriteUInt16(MajorOperatingSystemVersion); builder.WriteUInt16(MinorOperatingSystemVersion); builder.WriteUInt16(MajorImageVersion); builder.WriteUInt16(MinorImageVersion); builder.WriteUInt16(MajorSubsystemVersion); builder.WriteUInt16(MinorSubsystemVersion); // Win32VersionValue (reserved, should be 0) builder.WriteUInt32(0); // SizeOfImage: var lastSection = sections[sections.Length - 1]; builder.WriteUInt32((uint)BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, SectionAlignment)); // SizeOfHeaders: builder.WriteUInt32((uint)BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sections.Length, Is32Bit), FileAlignment)); // Checksum (TODO: not supported): builder.WriteUInt32(0); builder.WriteUInt16((ushort)Subsystem); builder.WriteUInt16((ushort)DllCharacteristics); if (Is32Bit) { builder.WriteUInt32((uint)SizeOfStackReserve); builder.WriteUInt32((uint)SizeOfStackCommit); builder.WriteUInt32((uint)SizeOfHeapReserve); builder.WriteUInt32((uint)SizeOfHeapCommit); } else { builder.WriteUInt64(SizeOfStackReserve); builder.WriteUInt64(SizeOfStackCommit); builder.WriteUInt64(SizeOfHeapReserve); builder.WriteUInt64(SizeOfHeapCommit); } // LoaderFlags builder.WriteUInt32(0); // The number of data-directory entries in the remainder of the header. builder.WriteUInt32(16); // directory entries: builder.WriteUInt32((uint)headers.ExportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ExportTable.Size); builder.WriteUInt32((uint)headers.ImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ImportTable.Size); builder.WriteUInt32((uint)headers.ResourceTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ResourceTable.Size); builder.WriteUInt32((uint)headers.ExceptionTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ExceptionTable.Size); builder.WriteUInt32((uint)headers.CertificateTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CertificateTable.Size); builder.WriteUInt32((uint)headers.BaseRelocationTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.BaseRelocationTable.Size); builder.WriteUInt32((uint)headers.DebugTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.DebugTable.Size); builder.WriteUInt32((uint)headers.CopyrightTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CopyrightTable.Size); builder.WriteUInt32((uint)headers.GlobalPointerTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.GlobalPointerTable.Size); builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.Size); builder.WriteUInt32((uint)headers.LoadConfigTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.LoadConfigTable.Size); builder.WriteUInt32((uint)headers.BoundImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.BoundImportTable.Size); builder.WriteUInt32((uint)headers.ImportAddressTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.ImportAddressTable.Size); builder.WriteUInt32((uint)headers.DelayImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.DelayImportTable.Size); builder.WriteUInt32((uint)headers.CorHeaderTable.RelativeVirtualAddress); builder.WriteUInt32((uint)headers.CorHeaderTable.Size); // Reserved, should be 0 builder.WriteUInt64(0); }
internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes) { int startOffset = builder.Count; // signature builder.WriteUInt32(0x424A5342); // major version builder.WriteUInt16(1); // minor version builder.WriteUInt16(1); // reserved builder.WriteUInt32(0); // Spec (section 24.2.1 Metadata Root): // Length ... Number of bytes allocated to hold version string (including null terminator), call this x. // Call the length of the string (including the terminator) m (we require m <= 255); // the length x is m rounded up to a multiple of four. builder.WriteInt32(sizes.MetadataVersionPaddedLength); int metadataVersionStart = builder.Count; builder.WriteUTF8(metadataVersion); builder.WriteByte(0); int metadataVersionEnd = builder.Count; for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++) { builder.WriteByte(0); } // reserved builder.WriteUInt16(0); // number of streams builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 1 : 0) + (sizes.IsStandaloneDebugMetadata ? 1 : 0))); // stream headers int offsetFromStartOfMetadata = sizes.MetadataHeaderSize; // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID if (sizes.IsStandaloneDebugMetadata) { SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder); } // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables; // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard. // // Note: EnC delta is stored as uncompressed metadata stream. SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder); SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder); if (sizes.IsEncDelta) { SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder); } int endOffset = builder.Count; Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize); }
private void SerializeFieldLayoutTable(BlobBuilder writer, MetadataSizes metadataSizes) { #if DEBUG for (int i = 1; i < _fieldLayoutTable.Count; i++) { Debug.Assert(_fieldLayoutTable[i - 1].Field < _fieldLayoutTable[i].Field); } #endif foreach (FieldLayoutRow fieldLayout in _fieldLayoutTable) { writer.WriteUInt32(fieldLayout.Offset); writer.WriteReference(fieldLayout.Field, metadataSizes.FieldDefIndexSize); } }