public static void AddManagedSections( this PEBuilder peBuilder, PEDirectoriesBuilder peDirectoriesBuilder, TypeSystemMetadataSerializer metadataSerializer, BlobBuilder ilStream, BlobBuilder mappedFieldData, BlobBuilder managedResourceData, Action<BlobBuilder, PESectionLocation> nativeResourceSectionSerializer, // opt int strongNameSignatureSize, // TODO MethodDefinitionHandle entryPoint, string pdbPathOpt, // TODO ContentId nativePdbContentId, // TODO ContentId portablePdbContentId, // TODO CorFlags corFlags) { int entryPointAddress = 0; // .text peBuilder.AddSection(".text", SectionCharacteristics.MemRead | SectionCharacteristics.MemExecute | SectionCharacteristics.ContainsCode, location => { var sectionBuilder = new BlobBuilder(); var metadataBuilder = new BlobBuilder(); var metadataSizes = metadataSerializer.MetadataSizes; var textSection = new ManagedTextSection( metadataSizes.MetadataSize, ilStreamSize: ilStream.Count, mappedFieldDataSize: mappedFieldData.Count, resourceDataSize: managedResourceData.Count, strongNameSignatureSize: strongNameSignatureSize, imageCharacteristics: peBuilder.ImageCharacteristics, machine: peBuilder.Machine, pdbPathOpt: pdbPathOpt, isDeterministic: peBuilder.IsDeterministic); int methodBodyStreamRva = location.RelativeVirtualAddress + textSection.OffsetToILStream; int mappedFieldDataStreamRva = location.RelativeVirtualAddress + textSection.CalculateOffsetToMappedFieldDataStream(); metadataSerializer.SerializeMetadata(metadataBuilder, methodBodyStreamRva, mappedFieldDataStreamRva); BlobBuilder debugTableBuilderOpt; if (pdbPathOpt != null || peBuilder.IsDeterministic) { debugTableBuilderOpt = new BlobBuilder(); textSection.WriteDebugTable(debugTableBuilderOpt, location, nativePdbContentId, portablePdbContentId); } else { debugTableBuilderOpt = null; } entryPointAddress = textSection.GetEntryPointAddress(location.RelativeVirtualAddress); textSection.Serialize( sectionBuilder, location.RelativeVirtualAddress, entryPoint.IsNil ? 0 : MetadataTokens.GetToken(entryPoint), corFlags, peBuilder.ImageBase, metadataBuilder, ilStream, mappedFieldData, managedResourceData, debugTableBuilderOpt); peDirectoriesBuilder.AddressOfEntryPoint = entryPointAddress; peDirectoriesBuilder.DebugTable = textSection.GetDebugDirectoryEntry(location.RelativeVirtualAddress); peDirectoriesBuilder.ImportAddressTable = textSection.GetImportAddressTableDirectoryEntry(location.RelativeVirtualAddress); peDirectoriesBuilder.ImportTable = textSection.GetImportTableDirectoryEntry(location.RelativeVirtualAddress); peDirectoriesBuilder.CorHeaderTable = textSection.GetCorHeaderDirectoryEntry(location.RelativeVirtualAddress); return sectionBuilder; }); // .rsrc if (nativeResourceSectionSerializer != null) { peBuilder.AddSection(".rsrc", SectionCharacteristics.MemRead | SectionCharacteristics.ContainsInitializedData, location => { var sectionBuilder = new BlobBuilder(); nativeResourceSectionSerializer(sectionBuilder, location); peDirectoriesBuilder.ResourceTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); return sectionBuilder; }); } // .reloc if (peBuilder.Machine == Machine.I386 || peBuilder.Machine == 0) { peBuilder.AddSection(".reloc", SectionCharacteristics.MemRead | SectionCharacteristics.MemDiscardable | SectionCharacteristics.ContainsInitializedData, location => { var sectionBuilder = new BlobBuilder(); WriteRelocSection(sectionBuilder, peBuilder.Machine, entryPointAddress); peDirectoriesBuilder.BaseRelocationTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); return sectionBuilder; }); } }
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); }
public void Serialize(BlobBuilder builder, PEDirectoriesBuilder headers, out ContentId contentId) { var serializedSections = SerializeSections(); Blob stampFixup; WritePESignature(builder); WriteCoffHeader(builder, serializedSections, out stampFixup); WritePEHeader(builder, headers, serializedSections); WriteSectionHeaders(builder, serializedSections); builder.Align(FileAlignment); foreach (var section in serializedSections) { builder.LinkSuffix(section.Builder); builder.Align(FileAlignment); } contentId = IdProvider(builder); // patch timestamp in COFF header: var stampWriter = new BlobWriter(stampFixup); stampWriter.WriteBytes(contentId.Stamp); Debug.Assert(stampWriter.RemainingBytes == 0); }