private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) { // TODO: we can precalculate the exact size of IL stream var ilWriter = new BlobWriter(32 * 1024); var metadataWriter = new BlobWriter(16 * 1024); var mappedFieldDataWriter = new BlobWriter(); var managedResourceWriter = new BlobWriter(1024); var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobWriter(16 * 1024) : null; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_module.PersistentIdentifier == default(Guid)); int moduleVersionIdOffsetInMetadataStream; var calculateMethodBodyStreamRva = new Func<MetadataSizes, int>(mdSizes => { FillInTextSectionHeader(mdSizes); return (int)_textSection.RelativeVirtualAddress + _sizeOfImportAddressTable + 72; }); int entryPointToken; MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( metadataWriter, debugMetadataWriterOpt, nativePdbWriterOpt, ilWriter, mappedFieldDataWriter, managedResourceWriter, calculateMethodBodyStreamRva, CalculateMappedFieldDataStreamRva, out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { if (entryPointToken != 0) { nativePdbWriterOpt.SetEntryPoint((uint)entryPointToken); } var assembly = _module.AsAssembly; if (assembly != null && assembly.Kind == ModuleKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(_module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(_module.GetSymbolToLocationMap()); #endif } nativePdbContentId = nativePdbWriterOpt.GetContentId(); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; } else { nativePdbContentId = default(ContentId); } FillInSectionHeaders(); // fill in header fields. FillInNtHeader(metadataSizes, CalculateMappedFieldDataStreamRva(metadataSizes)); var corHeader = CreateCorHeader(metadataSizes, entryPointToken); // write to PE stream. Stream peStream = getPeStream(); if (peStream == null) { return false; } long ntHeaderTimestampPosition; long metadataPosition; WriteHeaders(peStream, out ntHeaderTimestampPosition); WriteTextSection( peStream, corHeader, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, metadataSizes, nativePdbContentId, out metadataPosition); WriteRdataSection(peStream); WriteSdataSection(peStream); WriteCoverSection(peStream); WriteTlsSection(peStream); WriteResourceSection(peStream); WriteRelocSection(peStream); if (_deterministic) { var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); } return true; }
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) { // TODO: we can precalculate the exact size of IL stream var ilWriter = new BlobBuilder(32 * 1024); var metadataWriter = new BlobBuilder(16 * 1024); var mappedFieldDataWriter = new BlobBuilder(); var managedResourceWriter = new BlobBuilder(1024); var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobBuilder(16 * 1024) : null; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_properties.PersistentIdentifier == default(Guid)); int sectionCount = 1; if (_properties.RequiresStartupStub) sectionCount++; //.reloc if (!IteratorHelper.EnumerableIsEmpty(_nativeResourcesOpt) || _nativeResourceSectionOpt != null) sectionCount++; //.rsrc; int sizeOfPeHeaders = ComputeSizeOfPeHeaders(sectionCount); int textSectionRva = BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.SectionAlignment); int moduleVersionIdOffsetInMetadataStream; int methodBodyStreamRva = textSectionRva + OffsetToILStream; int entryPointToken; MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( metadataWriter, debugMetadataWriterOpt, nativePdbWriterOpt, ilWriter, mappedFieldDataWriter, managedResourceWriter, methodBodyStreamRva, mdSizes => CalculateMappedFieldDataStreamRva(textSectionRva, mdSizes), out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { var assembly = mdWriter.Module.AsAssembly; if (assembly != null && assembly.Kind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } nativePdbContentId = nativePdbWriterOpt.GetContentId(); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; } else { nativePdbContentId = default(ContentId); } // write to Portable PDB stream: ContentId portablePdbContentId; Stream portablePdbStream = getPortablePdbStreamOpt?.Invoke(); if (portablePdbStream != null) { debugMetadataWriterOpt.WriteContentTo(portablePdbStream); if (_deterministic) { portablePdbContentId = ContentId.FromHash(CryptographicHashProvider.ComputeSha1(portablePdbStream)); } else { portablePdbContentId = new ContentId(Guid.NewGuid().ToByteArray(), BitConverter.GetBytes(_timeStamp)); } } else { portablePdbContentId = default(ContentId); } // Only the size of the fixed part of the debug table goes here. DirectoryEntry debugDirectory = default(DirectoryEntry); DirectoryEntry importTable = default(DirectoryEntry); DirectoryEntry importAddressTable = default(DirectoryEntry); int entryPointAddress = 0; if (EmitPdb) { debugDirectory = new DirectoryEntry(textSectionRva + ComputeOffsetToDebugTable(metadataSizes), ImageDebugDirectoryBaseSize); } if (_properties.RequiresStartupStub) { importAddressTable = new DirectoryEntry(textSectionRva, SizeOfImportAddressTable); entryPointAddress = CalculateMappedFieldDataStreamRva(textSectionRva, metadataSizes) - (_is32bit ? 6 : 10); // TODO: constants importTable = new DirectoryEntry(textSectionRva + ComputeOffsetToImportTable(metadataSizes), (_is32bit ? 66 : 70) + 13); // TODO: constants } var corHeaderDirectory = new DirectoryEntry(textSectionRva + SizeOfImportAddressTable, size: CorHeaderSize); long ntHeaderTimestampPosition; long metadataPosition; List<SectionHeader> sectionHeaders = CreateSectionHeaders(metadataSizes, sectionCount); CoffHeader coffHeader; NtHeader ntHeader; FillInNtHeader(sectionHeaders, entryPointAddress, corHeaderDirectory, importTable, importAddressTable, debugDirectory, out coffHeader, out ntHeader); Stream peStream = getPeStream(); if (peStream == null) { return false; } WriteHeaders(peStream, ntHeader, coffHeader, sectionHeaders, out ntHeaderTimestampPosition); WriteTextSection( peStream, sectionHeaders[0], importTable.RelativeVirtualAddress, importAddressTable.RelativeVirtualAddress, entryPointToken, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, metadataSizes, nativePdbContentId, portablePdbContentId, out metadataPosition); var resourceSection = sectionHeaders.FirstOrDefault(s => s.Name == ResourceSectionName); if (resourceSection != null) { WriteResourceSection(peStream, resourceSection); } var relocSection = sectionHeaders.FirstOrDefault(s => s.Name == RelocationSectionName); if (relocSection != null) { WriteRelocSection(peStream, relocSection, entryPointAddress); } if (_deterministic) { var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); } return true; }
private void WritePeToStream(MetadataWriter mdWriter, Stream peStream, PdbWriter nativePdbWriterOpt, out uint entryPointToken) { // TODO: we can precalculate the exact size of IL stream var ilBuffer = new MemoryStream(32 * 1024); var ilWriter = new BinaryWriter(ilBuffer); var metadataBuffer = new MemoryStream(16 * 1024); var metadataWriter = new BinaryWriter(metadataBuffer); var mappedFieldDataBuffer = new MemoryStream(); var mappedFieldDataWriter = new BinaryWriter(mappedFieldDataBuffer); var managedResourceBuffer = new MemoryStream(1024); var managedResourceWriter = new BinaryWriter(managedResourceBuffer); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_module.PersistentIdentifier == default(Guid)); uint moduleVersionIdOffsetInMetadataStream; var calculateMethodBodyStreamRva = new Func<MetadataSizes, int>(mdSizes => { FillInTextSectionHeader(mdSizes); return (int)(_textSection.RelativeVirtualAddress + _sizeOfImportAddressTable + 72); }); MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( nativePdbWriterOpt, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, calculateMethodBodyStreamRva, CalculateMappedFieldDataStreamRva, out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); FillInSectionHeaders(); // fill in header fields. FillInNtHeader(metadataSizes, CalculateMappedFieldDataStreamRva(metadataSizes)); var corHeader = CreateCorHeader(metadataSizes, entryPointToken); // write to pe stream. long positionOfHeaderTimestamp; WriteHeaders(peStream, out positionOfHeaderTimestamp); long startOfMetadataStream; long positionOfDebugTableTimestamp; WriteTextSection( peStream, corHeader, metadataBuffer, ilBuffer, mappedFieldDataBuffer, managedResourceBuffer, out startOfMetadataStream, out positionOfDebugTableTimestamp); WriteRdataSection(peStream); WriteSdataSection(peStream); WriteCoverSection(peStream); WriteTlsSection(peStream); WriteResourceSection(peStream); WriteRelocSection(peStream); if (_deterministic) { var positionOfModuleVersionId = startOfMetadataStream + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, positionOfModuleVersionId, positionOfHeaderTimestamp, positionOfDebugTableTimestamp); } }