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++;
                    }
                }
            }
        }
Пример #2
0
 /// <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;
 }
Пример #3
0
        /// <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));
            }
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        public ObjectNode.ObjectData ToObjectData()
        {
            ObjectNode.ObjectData returnData = new ObjectNode.ObjectData(_data.ToArray(), 
                                                                         _relocs.ToArray(),
                                                                         Alignment,
                                                                         DefinedSymbols.ToArray());

            return returnData;
        }
Пример #7
0
        /// <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));
            }
        }
Пример #8
0
        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;
 }