void ComputeDependencySizeAndRelocData(ObjectNode.ObjectData objectData, Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets, List <ObjectNode> nodesToEmit, ref int totalAllocSizeNeeded, ref int nonObjectRelocTargets) { foreach (var reloc in objectData.Relocs) { DependencyNodeCore <NodeFactory> relocTargetAsNode = (DependencyNodeCore <NodeFactory>)reloc.Target; if (!relocTargets.ContainsKey(relocTargetAsNode)) { relocTargets.Add(relocTargetAsNode, null); ObjectNode relocTargetObjectNode = relocTargetAsNode as ObjectNode; if (relocTargetObjectNode != null) { UpdateBytesUsed(relocTargetObjectNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); nodesToEmit.Add(relocTargetObjectNode); } else { nonObjectRelocTargets++; } } } }
/// <summary> /// Initialize the list of relocations for a given object data item within the section. /// </summary> /// <param name="offset">Offset within the section</param> /// <param name="data">Object data block containing the list of relocations to fix up</param> public PlacedObjectData(int offset, ObjectNode.ObjectData data) { Offset = offset; Data = data; }
/// <summary> /// Add an ObjectData block to a given section. /// </summary> /// <param name="data">Block to add</param> /// <param name="sectionIndex">Section index</param> /// <param name="name">Node name to emit in the map file</param> /// <param name="mapFileBuilder">Optional map file to emit</param> public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, MapFileBuilder mapFileBuilder) { Section section = _sections[sectionIndex]; // Calculate alignment padding - apparently ObjectDataBuilder can produce an alignment of 0 int alignedOffset = section.Content.Count; if (objectData.Alignment > 1) { alignedOffset = (section.Content.Count + objectData.Alignment - 1) & -objectData.Alignment; int padding = alignedOffset - section.Content.Count; if (padding > 0) { if ((section.Characteristics & SectionCharacteristics.ContainsCode) != 0) { uint cp = _codePadding; while (padding >= sizeof(uint)) { section.Content.WriteUInt32(cp); padding -= sizeof(uint); } if (padding >= 2) { section.Content.WriteUInt16(unchecked ((ushort)cp)); cp >>= 16; } if ((padding & 1) != 0) { section.Content.WriteByte(unchecked ((byte)cp)); } } else { section.Content.WriteBytes(0, padding); } } } if (mapFileBuilder != null) { MapFileNode node = new MapFileNode(sectionIndex, alignedOffset, objectData.Data.Length, name); mapFileBuilder.AddNode(node); if (objectData.Relocs != null) { foreach (Relocation reloc in objectData.Relocs) { RelocType fileReloc = Relocation.GetFileRelocationType(reloc.RelocType); if (fileReloc != RelocType.IMAGE_REL_BASED_ABSOLUTE) { mapFileBuilder.AddRelocation(node, fileReloc); } } } } section.Content.WriteBytes(objectData.Data); if (objectData.DefinedSymbols != null) { foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols) { if (mapFileBuilder != null) { Utf8StringBuilder sb = new Utf8StringBuilder(); symbol.AppendMangledName(GetNameMangler(), sb); int sectionRelativeOffset = alignedOffset + symbol.Offset; mapFileBuilder.AddSymbol(new MapFileSymbol(sectionIndex, sectionRelativeOffset, sb.ToString())); } _symbolMap.Add(symbol, new SymbolTarget( sectionIndex: sectionIndex, offset: alignedOffset + symbol.Offset, size: objectData.Data.Length)); } } if (objectData.Relocs != null && objectData.Relocs.Length != 0) { section.PlacedObjectDataToRelocate.Add(new PlacedObjectData(alignedOffset, objectData)); } }
public ObjectNode.ObjectData ToObjectData() { #if DEBUG Debug.Assert(_numReservations == 0); #endif ObjectNode.ObjectData returnData = new ObjectNode.ObjectData(_data.ToArray(), _relocs.ToArray(), Alignment, DefinedSymbols.ToArray()); return returnData; }
private void PublishCode(MethodCodeNode methodCodeNodeNeedingCode) { var relocs = _relocs.ToArray(); Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); var objectData = new ObjectNode.ObjectData(_code, relocs, _compilation.NodeFactory.Target.MinimumFunctionAlignment, new ISymbolNode[] { methodCodeNodeNeedingCode }); methodCodeNodeNeedingCode.SetCode(objectData); methodCodeNodeNeedingCode.InitializeFrameInfos(_frameInfos); methodCodeNodeNeedingCode.InitializeDebugLocInfos(_debugLocInfos); }
public ObjectNode.ObjectData ToObjectData() { ObjectNode.ObjectData returnData = new ObjectNode.ObjectData(_data.ToArray(), _relocs.ToArray(), Alignment, DefinedSymbols.ToArray()); return returnData; }
/// <summary> /// Add an ObjectData block to a given section. /// </summary> /// <param name="data">Block to add</param> /// <param name="sectionIndex">Section index</param> /// <param name="name">Node name to emit in the map file</param> /// <param name="mapFile">Optional map file to emit</param> public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, TextWriter mapFile) { Section section = _sections[sectionIndex]; // Calculate alignment padding - apparently ObjectDataBuilder can produce an alignment of 0 int alignedOffset = section.Content.Count; if (objectData.Alignment > 1) { alignedOffset = (section.Content.Count + objectData.Alignment - 1) & -objectData.Alignment; int padding = alignedOffset - section.Content.Count; if (padding > 0) { if ((section.Characteristics & SectionCharacteristics.ContainsCode) != 0) { uint cp = _codePadding; while (padding >= sizeof(uint)) { section.Content.WriteUInt32(cp); padding -= sizeof(uint); } if (padding >= 2) { section.Content.WriteUInt16(unchecked ((ushort)cp)); cp >>= 16; } if ((padding & 1) != 0) { section.Content.WriteByte(unchecked ((byte)cp)); } } else { section.Content.WriteBytes(0, padding); } } } if (mapFile != null) { mapFile.WriteLine($@"S{sectionIndex}+0x{alignedOffset:X4}..{(alignedOffset + objectData.Data.Length):X4}: {objectData.Data.Length:X4} * {name}"); } section.Content.WriteBytes(objectData.Data); if (objectData.DefinedSymbols != null) { foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols) { if (mapFile != null) { Utf8StringBuilder sb = new Utf8StringBuilder(); symbol.AppendMangledName(GetNameMangler(), sb); int sectionRelativeOffset = alignedOffset + symbol.Offset; mapFile.WriteLine($@" +0x{sectionRelativeOffset:X4}: {sb.ToString()}"); } _symbolMap.Add(symbol, new SymbolTarget( sectionIndex: sectionIndex, offset: alignedOffset + symbol.Offset)); } } if (objectData.Relocs != null && objectData.Relocs.Length != 0) { section.PlacedObjectDataToRelocate.Add(new PlacedObjectData(alignedOffset, objectData)); } }
private void PublishCode() { var relocs = _relocs.ToArray(); Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); var objectData = new ObjectNode.ObjectData(_code, relocs, _compilation.NodeFactory.Target.MinimumFunctionAlignment, new ISymbolNode[] { _methodCodeNode }); _methodCodeNode.SetCode(objectData); _methodCodeNode.InitializeFrameInfos(_frameInfos); if (_ehClauses != null) _methodCodeNode.InitializeEHInfo(EncodeEHInfo()); _methodCodeNode.InitializeDebugLocInfos(_debugLocInfos); _methodCodeNode.InitializeDebugVarInfos(_debugVarInfos); }
public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs) { lock (this) { if (_corInfoImpl == null) { InitJitCodeManager(RuntimeAugments.RhGetOSModuleForMrt()); // TODO: Recycle jit interface object and TypeSystemContext _context = TypeSystemContextFactory.Create(); Compilation compilation = new Compilation(_context); _nodeFactory = compilation.NodeFactory; JitConfigProvider configProvider = new JitConfigProvider(new CorJitFlag[] { CorJitFlag.CORJIT_FLAG_DEBUG_CODE }, Array.Empty <KeyValuePair <string, string> >()); _corInfoImpl = new CorInfoImpl(compilation, configProvider); } MethodDesc methodToCompile = methodEntrypoint.MethodIdentifier.ToMethodDesc(_context); JitMethodCodeNode codeNode = new JitMethodCodeNode(methodToCompile); _corInfoImpl.CompileMethod(codeNode); ObjectNode.ObjectData codeData = codeNode.GetData(null, false); List <ObjectNode> nodesToEmit = new List <ObjectNode>(); Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets = new Dictionary <DependencyNodeCore <NodeFactory>, object>(); int totalAllocSizeNeeded = 0; int nonObjectRelocTargets = 0; nodesToEmit.Add(codeNode); UpdateBytesUsed(codeNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); int offsetOfEHData = totalAllocSizeNeeded; if (codeNode.EHInfo != null) { Debug.Assert(codeNode.EHInfo.Alignment == 1); // Assert needed as otherwise offsetOfEHData will be wrong UpdateBytesUsed(codeNode.EHInfo, ref totalAllocSizeNeeded); ComputeDependencySizeAndRelocData(codeNode.EHInfo, relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } for (int i = 0; i < nodesToEmit.Count; i++) { ObjectNode objNode = nodesToEmit[i]; ComputeDependencySizeAndRelocData(objNode.GetData(_nodeFactory, true), relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } if (nonObjectRelocTargets != 0) { totalAllocSizeNeeded = totalAllocSizeNeeded.AlignUp(IntPtr.Size); } int relocTargetOffsetStart = totalAllocSizeNeeded; DependencyNodeCore <NodeFactory>[] relocTargetsArray = new DependencyNodeCore <NodeFactory> [nonObjectRelocTargets]; { int iRelocTarget = 0; foreach (var relocTarget in relocTargets) { if (!(relocTarget.Key is ObjectNode)) { relocTargetsArray[iRelocTarget] = relocTarget.Key; totalAllocSizeNeeded += IntPtr.Size; iRelocTarget++; } } Debug.Assert(iRelocTarget == nonObjectRelocTargets); } GenericDictionaryCell[] genDictCells = new GenericDictionaryCell[relocTargetsArray.Length]; for (int iRelocTarget = 0; iRelocTarget < relocTargetsArray.Length; iRelocTarget++) { DependencyNodeCore <NodeFactory> relocTarget = relocTargetsArray[iRelocTarget]; GenericDictionaryCell newCell = null; if (relocTarget is ExternObjectSymbolNode) { var externObjectSymbolNode = (ExternObjectSymbolNode)relocTarget; var newMethodCell = externObjectSymbolNode.GetDictionaryCell(); newCell = newMethodCell; } if (newCell == null) { Environment.FailFast("Unknown reloc target type"); } genDictCells[iRelocTarget] = newCell; } IntPtr[] relocTargetsAsIntPtr = null; TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock( () => { TypeBuilderApi.ResolveMultipleCells(genDictCells, out relocTargetsAsIntPtr); }); // Layout of allocated memory... // ObjectNodes (aligned as appropriate) IntPtr pCodeManager; IntPtr jittedCode = AllocJittedCode(checked ((uint)totalAllocSizeNeeded), 8 /* TODO, alignment calculation */, out pCodeManager); int currentOffset = 0; foreach (var node in nodesToEmit) { ObjectNode.ObjectData objectData = node.GetData(_nodeFactory); EmitAndRelocData(objectData, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); // EHInfo doesn't get its own node, but it does get emitted into the stream. if ((node == codeNode) && (codeNode.EHInfo != null)) { Debug.Assert(offsetOfEHData == currentOffset); EmitAndRelocData(codeNode.EHInfo, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); } } foreach (IntPtr ptr in relocTargetsAsIntPtr) { currentOffset = currentOffset.AlignUp(IntPtr.Size); Marshal.WriteIntPtr(jittedCode, currentOffset, ptr); currentOffset += IntPtr.Size; } SetEHInfoPtr(pCodeManager, jittedCode, jittedCode + offsetOfEHData); IntPtr mainRuntimeFunction = IntPtr.Zero; for (int i = 0; i < codeNode.FrameInfos.Length; i++) { FrameInfo frame = codeNode.FrameInfos[i]; byte[] frameData = frame.BlobData; byte[] gcInfoData = Array.Empty <byte>(); byte[] gcInfoDataDeref = frameData; if (i == 0) { // For main function, add the gc info to the data gcInfoDataDeref = gcInfoData = codeNode.GCInfo; } IntPtr publishedFunction = PublishRuntimeFunction(pCodeManager, jittedCode, mainRuntimeFunction, checked ((uint)frame.StartOffset), checked ((uint)frame.EndOffset), frameData, checked ((uint)frameData.Length), gcInfoDataDeref, checked ((uint)gcInfoData.Length)); if (i == 0) { mainRuntimeFunction = publishedFunction; } } if (mainRuntimeFunction != IntPtr.Zero) { UpdateRuntimeFunctionTable(pCodeManager); } methodEntrypoint.MethodCode = jittedCode; return(jittedCode); } }
private void UpdateBytesUsed(ObjectNode.ObjectData nodeData, ref int bytesUsed) { bytesUsed = bytesUsed.AlignUp(nodeData.Alignment); bytesUsed += nodeData.Data.Length; return; }