/// <summary> /// Serialized #Pdb stream. /// </summary> protected override void SerializeStandalonePdbStream(BlobBuilder builder) { int startPosition = builder.Count; // the id will be filled in later _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize); builder.WriteInt32(_entryPoint.IsNil ? 0 : MetadataTokens.GetToken(_entryPoint)); builder.WriteUInt64(MetadataSizes.ExternalTablesMask); MetadataWriterUtilities.SerializeRowCounts(builder, MetadataSizes.ExternalRowCounts); int endPosition = builder.Count; Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition); }
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); }
public static void SerializeWin32Resources(BlobBuilder builder, ResourceSection resourceSections, int resourcesRva) { var sectionWriter = new BlobWriter(builder.ReserveBytes(resourceSections.SectionBytes.Length)); sectionWriter.WriteBytes(resourceSections.SectionBytes); var readStream = new MemoryStream(resourceSections.SectionBytes); var reader = new BinaryReader(readStream); foreach (int addressToFixup in resourceSections.Relocations) { sectionWriter.Offset = addressToFixup; reader.BaseStream.Position = addressToFixup; sectionWriter.WriteUInt32(reader.ReadUInt32() + (uint)resourcesRva); } }
private void WriteBlobHeap(BlobBuilder builder) { var writer = new BlobWriter(builder.ReserveBytes(_blobHeapSize)); // Perf consideration: With large heap the following loop may cause a lot of cache misses // since the order of entries in _blobs dictionary depends on the hash of the array values, // which is not correlated to the heap index. If we observe such issue we should order // the entries by heap position before running this loop. foreach (var entry in _blobs) { int heapOffset = MetadataTokens.GetHeapOffset(entry.Value); var blob = entry.Key; writer.Offset = heapOffset; writer.WriteCompressedInteger(blob.Length); writer.WriteBytes(blob); } }
public void ReserveBytes2() { var builder = new BlobBuilder(16); var writer = new BlobWriter(builder.ReserveBytes(17)); writer.WriteBytes(1, 17); var blobs = builder.GetBlobs().ToArray(); Assert.Equal(1, blobs.Length); AssertEx.Equal(new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, blobs[0].GetBytes().ToArray()); }
public void ReserveBytes1() { var builder = new BlobBuilder(16); var writer0 = new BlobWriter(builder.ReserveBytes(0)); var writer1 = new BlobWriter(builder.ReserveBytes(1)); var writer2 = new BlobWriter(builder.ReserveBytes(2)); Assert.Equal(3, builder.Count); AssertEx.Equal(new byte[] { 0, 0, 0 }, builder.ToArray()); Assert.Equal(0, writer0.Length); Assert.Equal(0, writer0.RemainingBytes); writer1.WriteBoolean(true); Assert.Equal(1, writer1.Length); Assert.Equal(0, writer1.RemainingBytes); writer2.WriteByte(1); Assert.Equal(2, writer2.Length); Assert.Equal(1, writer2.RemainingBytes); }
public void Link() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); var builder2 = new BlobBuilder(16); builder2.WriteByte(2); var builder3 = new BlobBuilder(16); builder3.WriteByte(3); var builder4 = new BlobBuilder(16); builder4.WriteByte(4); var builder5 = new BlobBuilder(16); builder5.WriteByte(5); builder2.LinkPrefix(builder1); AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder1.ToArray()); Assert.Throws<InvalidOperationException>(() => builder2.LinkPrefix(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteByte(0xff)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(1, 10)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 })); Assert.Throws<InvalidOperationException>(() => builder1.ReserveBytes(1)); Assert.Throws<InvalidOperationException>(() => builder1.GetBlobs()); Assert.Throws<InvalidOperationException>(() => builder1.ContentEquals(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF16("str")); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false)); builder2.LinkSuffix(builder3); AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder3.LinkPrefix(builder5)); builder2.LinkPrefix(builder4); AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder4.LinkPrefix(builder5)); builder2.LinkSuffix(builder5); AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.ToArray()); }
public void LinkSuffix_Empty3() { var builder1 = new BlobBuilder(16); builder1.ReserveBytes(16); builder1.ReserveBytes(0); var builder2 = new BlobBuilder(16); builder2.ReserveBytes(16); builder2.ReserveBytes(0); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 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 }, builder1.ToArray()); Assert.Equal(32, builder1.Count); Assert.Equal(16, builder2.Count); }
public Blob ReserveBytes(int byteCount) { return(_builder.ReserveBytes(byteCount)); }
/// <summary> /// Serializes .text section data into a specified <paramref name="builder"/>. /// </summary> /// <param name="builder">An empty builder to serialize section data to.</param> /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</param> /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPointTokenOrRelativeVirtualAddress"/>)</param> /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param> /// <param name="baseAddress">Base address of the PE image.</param> /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="mappedFieldDataBuilderOpt"><see cref="BlobBuilder"/> containing mapped field data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="resourceBuilderOpt"><see cref="BlobBuilder"/> containing managed resource data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="debugDataBuilderOpt"><see cref="BlobBuilder"/> containing PE debug table and data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="strongNameSignature">Blob reserved in the <paramref name="builder"/> for strong name signature.</param> public void Serialize( BlobBuilder builder, int relativeVirtualAddess, int entryPointTokenOrRelativeVirtualAddress, CorFlags corFlags, ulong baseAddress, BlobBuilder metadataBuilder, BlobBuilder ilBuilder, BlobBuilder?mappedFieldDataBuilderOpt, BlobBuilder?resourceBuilderOpt, BlobBuilder?debugDataBuilderOpt, out Blob strongNameSignature) { Debug.Assert(builder.Count == 0); Debug.Assert(metadataBuilder.Count == MetadataSize); Debug.Assert(metadataBuilder.Count % 4 == 0); Debug.Assert(ilBuilder.Count == ILStreamSize); Debug.Assert((mappedFieldDataBuilderOpt?.Count ?? 0) == MappedFieldDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) == ResourceDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) % 4 == 0); // TODO: avoid recalculation int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; if (RequiresStartupStub) { WriteImportAddressTable(builder, importTableRva); } WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); // IL: ilBuilder.Align(4); builder.LinkSuffix(ilBuilder); // metadata: builder.LinkSuffix(metadataBuilder); // managed resources: if (resourceBuilderOpt != null) { builder.LinkSuffix(resourceBuilderOpt); } // strong name signature: strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); // The bytes are required to be 0 for the purpose of calculating hash of the PE content // when strong name signing. new BlobWriter(strongNameSignature).WriteBytes(0, StrongNameSignatureSize); // debug directory and data: if (debugDataBuilderOpt != null) { builder.LinkSuffix(debugDataBuilderOpt); } if (RequiresStartupStub) { WriteImportTable(builder, importTableRva, importAddressTableRva); WriteNameTable(builder); WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); } // mapped field data: if (mappedFieldDataBuilderOpt != null) { builder.LinkSuffix(mappedFieldDataBuilderOpt); } Debug.Assert(builder.Count == ComputeSizeOfTextSection()); }
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); }