// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Debug = System.Diagnostics.Debug; namespace ILCompiler.DependencyAnalysis.ReadyToRun { /// <summary> /// Copies the metadata blob from input MSIL assembly to output ready-to-run image, fixing up Rvas to /// method IL bodies and FieldRvas. /// </summary> public class CopiedMetadataBlobNode : ObjectNode, ISymbolDefinitionNode { EcmaModule _sourceModule; public CopiedMetadataBlobNode(EcmaModule sourceModule) { _sourceModule = sourceModule; } public override ObjectNodeSection GetSection(NodeFactory factory) { return ObjectNodeSection.ReadOnlyDataSection; } public override bool IsShareable => false; public override int ClassCode => 635464644; public override bool StaticDependenciesAreComputed => true; public int Offset => 0; public int Size => _sourceModule.PEReader.GetMetadata().Length; private void WriteMethodTableRvas(NodeFactory factory, ref ObjectDataBuilder builder, ref BlobReader reader) { MetadataReader metadataReader = _sourceModule.MetadataReader; var tableIndex = TableIndex.MethodDef; int rowCount = metadataReader.GetTableRowCount(tableIndex); int rowSize = metadataReader.GetTableRowSize(tableIndex); for (int i = 1; i <= rowCount; i++) { Debug.Assert(builder.CountBytes == reader.Offset); int inputRva = reader.ReadInt32(); if (inputRva == 0) { // Don't fix up 0 Rvas (abstract methods in the methodDef table) builder.EmitInt(0); } else { var methodDefHandle = MetadataTokens.EntityHandle(TableIndex.MethodDef, i); EcmaMethod method = _sourceModule.GetMethod(methodDefHandle) as EcmaMethod; builder.EmitReloc(factory.CopiedMethodIL(method), RelocType.IMAGE_REL_BASED_ADDR32NB); } // Skip the rest of the row int remainingBytes = rowSize - sizeof(int); builder.EmitBytes(reader.ReadBytes(remainingBytes)); } } private void WriteFieldRvas(NodeFactory factory, ref ObjectDataBuilder builder, ref BlobReader reader) { MetadataReader metadataReader = _sourceModule.MetadataReader; var tableIndex = TableIndex.FieldRva; int rowCount = metadataReader.GetTableRowCount(tableIndex); bool compressedFieldRef = 6 == metadataReader.GetTableRowSize(TableIndex.FieldRva); for (int i = 1; i <= rowCount; i++) { Debug.Assert(builder.CountBytes == reader.Offset); // Rva reader.ReadInt32(); int fieldToken; if (compressedFieldRef) { fieldToken = reader.ReadUInt16(); } else { fieldToken = reader.ReadInt32(); } EntityHandle fieldHandle = MetadataTokens.EntityHandle(TableIndex.Field, fieldToken); EcmaField fieldDesc = _sourceModule.GetField((FieldDefinitionHandle)fieldHandle); Debug.Assert(fieldDesc.HasRva); builder.EmitReloc(factory.CopiedFieldRva(fieldDesc), RelocType.IMAGE_REL_BASED_ADDR32NB); if (compressedFieldRef) { builder.EmitUShort((ushort)fieldToken); } else { builder.EmitUInt((uint)fieldToken); } } } public unsafe override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.RequireInitialPointerAlignment(); builder.AddSymbol(this); BlobReader metadataBlob = new BlobReader(_sourceModule.PEReader.GetMetadata().Pointer, _sourceModule.PEReader.GetMetadata().Length); var metadataReader = _sourceModule.MetadataReader; // // methodDef table // int methodDefTableOffset = metadataReader.GetTableMetadataOffset(TableIndex.MethodDef); builder.EmitBytes(metadataBlob.ReadBytes(methodDefTableOffset)); WriteMethodTableRvas(factory, ref builder, ref metadataBlob); // // fieldRva table // int fieldRvaTableOffset = metadataReader.GetTableMetadataOffset(TableIndex.FieldRva); builder.EmitBytes(metadataBlob.ReadBytes(fieldRvaTableOffset - metadataBlob.Offset)); WriteFieldRvas(factory, ref builder, ref metadataBlob); // Copy the rest of the metadata blob builder.EmitBytes(metadataBlob.ReadBytes(metadataReader.MetadataLength - metadataBlob.Offset)); Debug.Assert(builder.CountBytes == metadataBlob.Length); Debug.Assert(builder.CountBytes == metadataBlob.Offset); Debug.Assert(builder.CountBytes == Size); return builder.ToObjectData(); } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append("__MetadataBlob"u8); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { return _sourceModule.CompareTo(((CopiedMetadataBlobNode)other)._sourceModule); } } } |