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 override void Write(MDWriter mdWriter, uint rva, MDWriterStream stream) { RVA = rva; var startPos = stream.Position; // PERF: We only write the known needed heaps. The #US heap isn't written since // it's only used by method bodies and we don't write method bodies. var heapWriters = new List <MDHeapWriter>(4); heapWriters.Add(new TablesHeapWriter(mdEditor.TablesHeap, mdEditor.StringsHeap, mdEditor.GuidHeap, mdEditor.BlobHeap)); if (mdEditor.StringsHeap.ExistsInMetadata || mdEditor.StringsHeap.MustRewriteHeap()) { heapWriters.Add(new StringsHeapWriter(mdEditor.StringsHeap)); } if (mdEditor.GuidHeap.ExistsInMetadata || mdEditor.GuidHeap.MustRewriteHeap()) { heapWriters.Add(new GuidHeapWriter(mdEditor.GuidHeap)); } if (mdEditor.BlobHeap.ExistsInMetadata || mdEditor.BlobHeap.MustRewriteHeap()) { heapWriters.Add(new BlobHeapWriter(mdEditor.BlobHeap)); } var heapInfos = new(long offsetAndSizePosition, long dataPosition, long dataEndPosition)[heapWriters.Count];
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(); } }
public abstract void Write(MDWriter mdWriter, MDWriterStream stream, byte[] tempBuffer);