protected void WriteData(MDWriterStream stream, List <byte[]> newData, byte[] tempBuffer) { if (newData.Count == 0) { return; } int tempBufferIndex = 0; foreach (var data in newData) { int bytesLeft = tempBuffer.Length - tempBufferIndex; if (data.Length > bytesLeft) { stream.Write(tempBuffer, 0, tempBufferIndex); tempBufferIndex = 0; } if (data.Length > tempBuffer.Length) { Debug.Assert(tempBufferIndex == 0); stream.Write(data); } else { Array.Copy(data, 0, tempBuffer, tempBufferIndex, data.Length); tempBufferIndex += data.Length; } } if (tempBufferIndex > 0) { stream.Write(tempBuffer, 0, tempBufferIndex); } }
public override void Finish(MDWriter mdWriter, MDWriterStream stream) { stream.Position = cor20HeaderMetadataDataDirPosition; Debug.Assert(mdData.RVA != 0); Debug.Assert(mdData.Size != 0); stream.Write(mdData.RVA); stream.Write(mdData.Size); if (!(snData is null)) { stream.Position = cor20HeaderStrongnameDataDirPosition; Debug.Assert(snData.RVA != 0); Debug.Assert(snData.Size != 0); stream.Write(snData.RVA); stream.Write(snData.Size); } }
public override void Write(MDWriter mdWriter, uint rva, MDWriterStream stream) { mdWriter.WriteDataDirectory(14, rva, headerSize); stream.Write(headerSize); var cor20 = mdWriter.MetadataEditor.RealMetadata.ImageCor20Header; stream.Write(cor20.MajorRuntimeVersion); stream.Write(cor20.MinorRuntimeVersion); cor20HeaderMetadataDataDirPosition = stream.Position; stream.Position += 8; // Metadata data directory, updated later var flags = cor20.Flags; flags &= ~ComImageFlags.NativeEntryPoint; if (snData is null) { flags &= ~ComImageFlags.StrongNameSigned; } else { flags |= ComImageFlags.StrongNameSigned; } stream.Write((uint)flags); if ((cor20.Flags & ComImageFlags.NativeEntryPoint) == 0) { stream.Write(cor20.EntryPointToken_or_RVA); } else { stream.Position += 4; } stream.Position += 8; // .NET resources cor20HeaderStrongnameDataDirPosition = stream.Position; stream.Position += 8; // Strong name signature stream.Position += 8; // Code manager table stream.Position += 8; // Vtable fixups stream.Position += 8; // Export address table jumps stream.Position += 8; // Managed native header }
public void Write() { var peImage = mdEditor.RealMetadata.PEImage; bool is32Bit = peImage.ImageNTHeaders.OptionalHeader is ImageOptionalHeader32; sections.Add(textSection = new PESection(".text", 0x60000020)); StrongNameSignatureSectionData snData = null; var cor20 = mdEditor.RealMetadata.ImageCor20Header; if ((cor20.Flags & ComImageFlags.StrongNameSigned) != 0 && cor20.StrongNameSignature.Size != 0 && cor20.StrongNameSignature.VirtualAddress != 0) { snData = new StrongNameSignatureSectionData(cor20.StrongNameSignature.Size); } if (snData != null) { textSection.SectionData.Add(snData); } var mdData = new DotNetMetadataSectionData(mdEditor); textSection.SectionData.Add(new ImageCor20HeaderSectionData(mdData, snData)); textSection.SectionData.Add(mdData); // DOS MZ header stream.Write(dosHeader); // PE\0\0 Debug.Assert(stream.Position == BitConverter.ToUInt32(dosHeader, 0x7C)); stream.Write(0x00004550); // IMAGE_FILE_HEADER var ifh = peImage.ImageNTHeaders.FileHeader; stream.Write((ushort)ifh.Machine); Debug.Assert(sections.Count <= ushort.MaxValue); stream.Write((ushort)sections.Count); stream.Write(ifh.TimeDateStamp); stream.Position += 8; // PointerToSymbolTable & NumberOfSymbols stream.Write((ushort)(is32Bit ? 0xE0 : 0xF0)); stream.Write((ushort)ifh.Characteristics); // IMAGE_OPTIONAL_HEADER var optHeaderPos = stream.Position; if (is32Bit) { var opt = (ImageOptionalHeader32)peImage.ImageNTHeaders.OptionalHeader; var start = stream.Position; stream.Write(opt.Magic); stream.Write(opt.MajorLinkerVersion); stream.Write(opt.MinorLinkerVersion); // SizeOfCode, SizeOfInitializedData, SizeOfUninitializedData // AddressOfEntryPoint, BaseOfCode, BaseOfData stream.Position += 6 * 4; stream.Write((uint)opt.ImageBase); stream.Write((uint)SectionAlignment); stream.Write((uint)FileAlignment); stream.Write(opt.MajorOperatingSystemVersion); stream.Write(opt.MinorOperatingSystemVersion); stream.Write(opt.MajorImageVersion); stream.Write(opt.MinorImageVersion); stream.Write(opt.MajorSubsystemVersion); stream.Write(opt.MinorSubsystemVersion); stream.Write(opt.Win32VersionValue); // SizeOfImage, SizeOfHeaders, CheckSum stream.Position += 3 * 4; stream.Write((ushort)opt.Subsystem); stream.Write((ushort)opt.DllCharacteristics); stream.Write((uint)opt.SizeOfStackReserve); stream.Write((uint)opt.SizeOfStackCommit); stream.Write((uint)opt.SizeOfHeapReserve); stream.Write((uint)opt.SizeOfHeapCommit); stream.Write(opt.LoaderFlags); stream.Write(0x10); // NumberOfRvaAndSizes Debug.Assert((stream.Position - start) == 0x60); } else { var opt = (ImageOptionalHeader64)peImage.ImageNTHeaders.OptionalHeader; var start = stream.Position; stream.Write(opt.Magic); stream.Write(opt.MajorLinkerVersion); stream.Write(opt.MinorLinkerVersion); // SizeOfCode, SizeOfInitializedData, SizeOfUninitializedData // AddressOfEntryPoint, BaseOfCode stream.Position += 5 * 4; stream.Write(opt.ImageBase); stream.Write((uint)SectionAlignment); stream.Write((uint)FileAlignment); stream.Write(opt.MajorOperatingSystemVersion); stream.Write(opt.MinorOperatingSystemVersion); stream.Write(opt.MajorImageVersion); stream.Write(opt.MinorImageVersion); stream.Write(opt.MajorSubsystemVersion); stream.Write(opt.MinorSubsystemVersion); stream.Write(opt.Win32VersionValue); // SizeOfImage, SizeOfHeaders, CheckSum stream.Position += 3 * 4; stream.Write((ushort)opt.Subsystem); stream.Write((ushort)opt.DllCharacteristics); stream.Write(opt.SizeOfStackReserve); stream.Write(opt.SizeOfStackCommit); stream.Write(opt.SizeOfHeapReserve); stream.Write(opt.SizeOfHeapCommit); stream.Write(opt.LoaderFlags); stream.Write(0x10); // NumberOfRvaAndSizes Debug.Assert((stream.Position - start) == 0x70); } // IMAGE_DATA_DIRECTORY dataDirPosition = stream.Position; stream.Position += 0x10 * 8; // IMAGE_SECTION_HEADER var sectionPos = stream.Position; foreach (var section in sections) { Debug.Assert(section.Name.Length == 8); stream.Write(section.Name); // VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData // PointerToRelocations, PointerToLinenumbers, NumberOfRelocations, NumberOfLinenumbers stream.Position += 6 * 4 + 2 * 2; stream.Write(section.Characteristics); } uint headerLength = (uint)stream.Position; AlignUp(FileAlignment); // Write all sections uint rva = SectionAlignment; foreach (var section in sections) { section.VirtualAddress = rva; section.PointerToRawData = (uint)stream.Position; foreach (var data in section.SectionData) { var pos = stream.Position; AlignUp(data.Alignment); rva += (uint)(stream.Position - pos); pos = stream.Position; data.Write(this, rva, stream); rva += (uint)(stream.Position - pos); } Debug.Assert(stream.Position != section.PointerToRawData); if (stream.Position == section.PointerToRawData) { stream.Position++; } section.VirtualSize = (uint)stream.Position - section.PointerToRawData; section.SizeOfRawData = ((uint)stream.Position - section.PointerToRawData + FileAlignment - 1) & ~(FileAlignment - 1); rva = (rva + SectionAlignment - 1) & ~(SectionAlignment - 1); AlignUp(FileAlignment); } stream.Length = stream.Position; // Update IMAGE_SECTION_HEADER stream.Position = sectionPos; foreach (var section in sections) { stream.Position += 8; stream.Write(section.VirtualSize); stream.Write(section.VirtualAddress); stream.Write(section.SizeOfRawData); stream.Write(section.PointerToRawData); stream.Position += 16; } // Update IMAGE_OPTIONAL_HEADER var sectionSizes = new SectionSizes(FileAlignment, SectionAlignment, headerLength, () => GetSectionSizeInfos()); stream.Position = optHeaderPos; if (is32Bit) { var opt = (ImageOptionalHeader32)peImage.ImageNTHeaders.OptionalHeader; stream.Position += 4; stream.Write(sectionSizes.SizeOfCode); stream.Write(sectionSizes.SizeOfInitdData); stream.Write(sectionSizes.SizeOfUninitdData); stream.Position += 4; stream.Write(sectionSizes.BaseOfCode); stream.Write(sectionSizes.BaseOfData); stream.Position += 0x1C; stream.Write(sectionSizes.SizeOfImage); stream.Write(sectionSizes.SizeOfHeaders); } else { var opt = (ImageOptionalHeader64)peImage.ImageNTHeaders.OptionalHeader; stream.Position += 4; stream.Write(sectionSizes.SizeOfCode); stream.Write(sectionSizes.SizeOfInitdData); stream.Write(sectionSizes.SizeOfUninitdData); stream.Position += 4; stream.Write(sectionSizes.BaseOfCode); stream.Position += 0x20; stream.Write(sectionSizes.SizeOfImage); stream.Write(sectionSizes.SizeOfHeaders); } foreach (var section in sections) { foreach (var data in section.SectionData) { data.Finish(this, stream); } } }
public unsafe override void Write(MDWriter mdWriter, MDWriterStream stream, byte[] tempBuffer) { var tblStream = mdWriter.MetadataEditor.RealMetadata.TablesStream; stream.Write(tblStream.Reserved1); stream.Write((byte)(tblStream.Version >> 8)); stream.Write((byte)tblStream.Version); stream.Write((byte)mdStreamFlags); stream.Write((byte)1); stream.Write(GetValidMask(tablesHeap)); stream.Write(GetSortedMask(tablesHeap, tblStream.SortedMask)); var rowCounts = new uint[tablesHeap.TableInfos.Length]; var infos = tablesHeap.TableInfos; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info != null && !info.IsEmpty) { rowCounts[i] = info.Rows; stream.Write(info.Rows); } } var dnTableSizes = new DotNetTableSizes(); var tableInfos = dnTableSizes.CreateTables((byte)(tblStream.Version >> 8), (byte)tblStream.Version); dnTableSizes.InitializeSizes((mdStreamFlags & MDStreamFlags.BigStrings) != 0, (mdStreamFlags & MDStreamFlags.BigGUID) != 0, (mdStreamFlags & MDStreamFlags.BigBlob) != 0, rowCounts, rowCounts); long totalSize = 0; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info != null && !info.IsEmpty) { totalSize += (long)info.Rows * tableInfos[i].RowSize; } } // NOTE: We don't write method bodies or field data, the compiler shouldn't // read Method.RVA. We also don't write the FieldRVA table. // PERF: Write to a temp buffer followed by a call to stream.Write(byte[]). It's faster // than calling stream.Write() for every row + column. var tablesPos = stream.Position; int tempBufferIndex = 0; for (int i = 0; i < infos.Length; i++) { if (tablesToIgnore[i]) { continue; } var info = infos[i]; if (info == null || info.IsEmpty) { continue; } var tableWriter = TableWriter.Create(info); var mdTable = info.MDTable; var tbl = tableInfos[i]; var columns = tbl.Columns; var rows = tableWriter.Rows; uint currentRowIndex = 0; var rowSize = (uint)tbl.RowSize; Debug.Assert(tempBuffer.Length >= rowSize, "Temp buffer is too small"); // If there are no changes in the original metadata or layout, just copy everything uint unmodifiedRows = tableWriter.FirstModifiedRowId - 1; if (unmodifiedRows > 0 && Equals(mdTable.TableInfo, tbl)) { if (tempBufferIndex > 0) { stream.Write(tempBuffer, 0, tempBufferIndex); tempBufferIndex = 0; } stream.Write((byte *)mdWriter.ModuleData.Pointer + (int)mdTable.StartOffset, (int)(unmodifiedRows * mdTable.RowSize)); Debug.Assert(unmodifiedRows <= rows); rows -= unmodifiedRows; currentRowIndex += unmodifiedRows; } while (rows > 0) { int bytesLeft = tempBuffer.Length - tempBufferIndex; uint maxRows = Math.Min((uint)bytesLeft / rowSize, rows); if (maxRows == 0) { stream.Write(tempBuffer, 0, tempBufferIndex); tempBufferIndex = 0; bytesLeft = tempBuffer.Length; maxRows = Math.Min((uint)bytesLeft / rowSize, rows); } Debug.Assert(maxRows > 0); for (uint endRowIndex = currentRowIndex + maxRows; currentRowIndex < endRowIndex; currentRowIndex++, tempBufferIndex += (int)rowSize) { tableWriter.WriteRow(currentRowIndex, columns, tempBuffer, tempBufferIndex); } rows -= maxRows; } } if (tempBufferIndex > 0) { stream.Write(tempBuffer, 0, tempBufferIndex); } if (tablesPos + totalSize != stream.Position) { throw new InvalidOperationException(); } }