From 790a8d39b798032946c1b04384f43948513f2400 Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Fri, 6 Mar 2020 23:09:55 +0900 Subject: [PATCH] Support rodata relocations in crossgen2 for ARM32 (#33153) --- .../Compiler/DependencyAnalysis/Relocation.cs | 33 +++---- ...lobNode.cs => SettableReadOnlyDataBlob.cs} | 25 +++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 85 +++++++++++++------ .../ReadyToRunCodegenNodeFactory.cs | 31 ++----- .../ILCompiler.ReadyToRun.csproj | 2 +- .../ObjectWriter/RelocationHelper.cs | 8 ++ 6 files changed, 107 insertions(+), 77 deletions(-) rename src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/{BlobNode.cs => SettableReadOnlyDataBlob.cs} (66%) diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 8ac7cdb1d1266..13d7358dd65b1 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -8,19 +8,20 @@ namespace ILCompiler.DependencyAnalysis { public enum RelocType { - IMAGE_REL_BASED_ABSOLUTE = 0x00, // No relocation required - IMAGE_REL_BASED_ADDR32NB = 0x02, // The 32-bit address without an image base (RVA) - IMAGE_REL_BASED_HIGHLOW = 0x03, // 32 bit address base - IMAGE_REL_BASED_THUMB_MOV32 = 0x07, // Thumb2: based MOVW/MOVT - IMAGE_REL_BASED_DIR64 = 0x0A, // 64 bit address base - IMAGE_REL_BASED_REL32 = 0x10, // 32-bit relative address from byte following reloc - IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL - IMAGE_REL_BASED_ARM64_BRANCH26 = 0x14, // Arm64: B, BL - IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc - // This is a special NGEN-specific relocation type - // for relative pointer (used to make NGen relocation - // section smaller) - IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target + IMAGE_REL_BASED_ABSOLUTE = 0x00, // No relocation required + IMAGE_REL_BASED_ADDR32NB = 0x02, // The 32-bit address without an image base (RVA) + IMAGE_REL_BASED_HIGHLOW = 0x03, // 32 bit address base + IMAGE_REL_BASED_THUMB_MOV32 = 0x07, // Thumb2: based MOVW/MOVT + IMAGE_REL_BASED_DIR64 = 0x0A, // 64 bit address base + IMAGE_REL_BASED_REL32 = 0x10, // 32-bit relative address from byte following reloc + IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL + IMAGE_REL_BASED_THUMB_MOV32_PCREL = 0x14, // Thumb2: based MOVW/MOVT + IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL + IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc + // This is a special NGEN-specific relocation type + // for relative pointer (used to make NGen relocation + // section smaller) + IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 = 0x81, // ADRP IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset @@ -29,8 +30,8 @@ public enum RelocType // // Relocations for R2R image production // - IMAGE_REL_SYMBOL_SIZE = 0x1000, // The size of data in the image represented by the target symbol node - IMAGE_REL_FILE_ABSOLUTE = 0x1001, // 32 bit offset from begining of image + IMAGE_REL_SYMBOL_SIZE = 0x1000, // The size of data in the image represented by the target symbol node + IMAGE_REL_FILE_ABSOLUTE = 0x1001, // 32 bit offset from begining of image } public struct Relocation @@ -280,6 +281,7 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v *(long*)location = value; break; case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + case RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL: PutThumb2Mov32((ushort*)location, (uint)value); break; case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: @@ -313,6 +315,7 @@ public static unsafe long ReadValue(RelocType relocType, void* location) case RelocType.IMAGE_REL_BASED_DIR64: return *(long*)location; case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + case RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL: return (long)GetThumb2Mov32((ushort*)location); case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: return (long)GetThumb2BlRel24((ushort*)location); diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs similarity index 66% rename from src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs rename to src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs index 083de9bded898..bf7de904bb351 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/BlobNode.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs @@ -3,29 +3,27 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using Internal.Text; using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis { - public class BlobNode : ObjectNode, ISymbolDefinitionNode + public class SettableReadOnlyDataBlob : ObjectNode, ISymbolDefinitionNode { private Utf8String _name; private ObjectNodeSection _section; - private byte[] _data; - private int _alignment; + private ObjectData _data; - public BlobNode(Utf8String name, ObjectNodeSection section, byte[] data, int alignment) + public SettableReadOnlyDataBlob(Utf8String name, ObjectNodeSection section) { _name = name; _section = section; - _data = data; - _alignment = alignment; } public override ObjectNodeSection Section => _section; - public override bool StaticDependenciesAreComputed => true; + public override bool StaticDependenciesAreComputed => _data != null; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { @@ -34,20 +32,27 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) public int Offset => 0; public override bool IsShareable => true; + public void InitializeData(ObjectData data) + { + Debug.Assert(_data == null); + _data = data; + } + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { - return new ObjectData(_data, Array.Empty(), _alignment, new ISymbolDefinitionNode[] { this }); + return _data; } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); #if !SUPPORT_JIT - public override int ClassCode => -470351029; + public override int ClassCode => 674507768; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { - return _name.CompareTo(((BlobNode)other)._name); + return _name.CompareTo(((SettableReadOnlyDataBlob)other)._name); } #endif } } + diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs index 30731de43bc50..939d8294a4a1e 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -218,11 +218,12 @@ private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, Method } PublishCode(); + PublishROData(); } private void PublishCode() { - var relocs = _relocs.ToArray(); + var relocs = _codeRelocs.ToArray(); Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); int alignment = JitConfigProvider.Instance.HasFlag(CorJitFlag.CORJIT_FLAG_SIZE_OPT) ? @@ -267,6 +268,23 @@ private void PublishCode() PublishProfileData(); } + private void PublishROData() + { + if (_roDataBlob == null) + { + return; + } + + var relocs = _roDataRelocs.ToArray(); + Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); + var objectData = new ObjectNode.ObjectData(_roData, + relocs, + _roDataAlignment, + new ISymbolDefinitionNode[] { _roDataBlob }); + + _roDataBlob.InitializeData(objectData); + } + partial void PublishProfileData(); private MethodDesc MethodBeingCompiled @@ -321,7 +339,8 @@ private void CompileMethodCleanup() _roData = null; _roDataBlob = null; - _relocs = new ArrayBuilder(); + _codeRelocs = new ArrayBuilder(); + _roDataRelocs = new ArrayBuilder(); _numFrameInfos = 0; _usedFrameInfos = 0; @@ -2495,7 +2514,8 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) private byte[] _roData; - private BlobNode _roDataBlob; + private SettableReadOnlyDataBlob _roDataBlob; + private int _roDataAlignment; private int _numFrameInfos; private int _usedFrameInfos; @@ -2523,26 +2543,25 @@ private void allocMem(uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint if (roDataSize != 0) { - int alignment = 8; + _roDataAlignment = 8; if ((flag & CorJitAllocMemFlag.CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN) != 0) { - alignment = 32; + _roDataAlignment = 32; } else if ((flag & CorJitAllocMemFlag.CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN) != 0) { - alignment = 16; + _roDataAlignment = 16; } else if (roDataSize < 8) { - alignment = PointerSize; + _roDataAlignment = PointerSize; } _roData = new byte[roDataSize]; - _roDataBlob = _compilation.NodeFactory.ReadOnlyDataBlob( - "__readonlydata_" + _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled), - _roData, alignment); + _roDataBlob = _compilation.NodeFactory.SettableReadOnlyDataBlob( + "__readonlydata_" + _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled)); roDataBlock = (void*)GetPin(_roData); } @@ -2611,7 +2630,9 @@ private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO { } - private ArrayBuilder _relocs; + private ArrayBuilder _codeRelocs; + private ArrayBuilder _roDataRelocs; + /// /// Various type of block. @@ -2679,6 +2700,21 @@ private BlockType findKnownBlock(void* location, out int offset) partial void findKnownBBCountBlock(ref BlockType blockType, void* location, ref int offset); + private ref ArrayBuilder findRelocBlock(BlockType blockType, out int length) + { + switch (blockType) + { + case BlockType.Code: + length = _code.Length; + return ref _codeRelocs; + case BlockType.ROData: + length = _roData.Length; + return ref _roDataRelocs; + default: + throw new NotImplementedException("Arbitrary relocs"); + } + } + // Translates relocation type constants used by JIT (defined in winnt.h) to RelocType enumeration private static RelocType GetRelocType(TargetArchitecture targetArchitecture, ushort fRelocType) { @@ -2709,15 +2745,8 @@ private void recordRelocation(void* location, void* target, ushort fRelocType, u BlockType locationBlock = findKnownBlock(location, out relocOffset); Debug.Assert(locationBlock != BlockType.Unknown, "BlockType.Unknown not expected"); - TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; - - if (locationBlock != BlockType.Code) - { - // TODO: https://github.com/dotnet/corert/issues/3877 - if (targetArchitecture == TargetArchitecture.ARM) - return; - throw new NotImplementedException("Arbitrary relocs"); - } + int length; + ref ArrayBuilder sourceBlock = ref findRelocBlock(locationBlock, out length); int relocDelta; BlockType targetBlock = findKnownBlock(target, out relocDelta); @@ -2752,13 +2781,14 @@ private void recordRelocation(void* location, void* target, ushort fRelocType, u relocDelta += addlDelta; + TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; RelocType relocType = GetRelocType(targetArchitecture, fRelocType); // relocDelta is stored as the value Relocation.WriteValue(relocType, location, relocDelta); - if (_relocs.Count == 0) - _relocs.EnsureCapacity(_code.Length / 32 + 1); - _relocs.Add(new Relocation(relocType, relocOffset, relocTarget)); + if (sourceBlock.Count == 0) + sourceBlock.EnsureCapacity(length / 32 + 1); + sourceBlock.Add(new Relocation(relocType, relocOffset, relocTarget)); } private ushort getRelocTypeHint(void* target) @@ -2819,8 +2849,13 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) flags.Set(CorJitFlag.CORJIT_FLAG_PREJIT); flags.Set(CorJitFlag.CORJIT_FLAG_USE_PINVOKE_HELPERS); - if ((_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X86 - || _compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.X64) + TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; + + if (targetArchitecture == TargetArchitecture.ARM && !_compilation.TypeSystemContext.Target.IsWindows) + flags.Set(CorJitFlag.CORJIT_FLAG_RELATIVE_CODE_RELOCS); + + if ((targetArchitecture == TargetArchitecture.X86 + || targetArchitecture == TargetArchitecture.X64) #if READYTORUN && isMethodDefinedInCoreLib() #endif diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 6a3e4ef56c19b..105719a988db3 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -99,11 +99,11 @@ public ISymbolNode ReadyToRunHelperFromTypeLookup(ReadyToRunHelperId id, Object return _genericReadyToRunHelpersFromType.GetOrAdd(new ReadyToRunGenericHelperKey(id, target, dictionaryOwner)); } - private NodeCache _readOnlyDataBlobs; + private NodeCache _readOnlyDataBlobs; - public BlobNode ReadOnlyDataBlob(Utf8String name, byte[] blobData, int alignment) + public SettableReadOnlyDataBlob SettableReadOnlyDataBlob(Utf8String name) { - return _readOnlyDataBlobs.GetOrAdd(new ReadOnlyDataBlobKey(name, blobData, alignment)); + return _readOnlyDataBlobs.GetOrAdd(name); } private struct ReadyToRunGenericHelperKey : IEquatable @@ -131,27 +131,6 @@ public override int GetHashCode() } } - private struct ReadOnlyDataBlobKey : IEquatable - { - public readonly Utf8String Name; - public readonly byte[] Data; - public readonly int Alignment; - - public ReadOnlyDataBlobKey(Utf8String name, byte[] data, int alignment) - { - Name = name; - Data = data; - Alignment = alignment; - } - - // The assumption here is that the name of the blob is unique. - // We can't emit two blobs with the same name and different contents. - // The name is part of the symbolic name and we don't do any mangling on it. - public bool Equals(ReadOnlyDataBlobKey other) => Name.Equals(other.Name); - public override bool Equals(object obj) => obj is ReadOnlyDataBlobKey && Equals((ReadOnlyDataBlobKey)obj); - public override int GetHashCode() => Name.GetHashCode(); - } - private struct ModuleAndIntValueKey : IEquatable { public readonly int IntValue; @@ -235,9 +214,9 @@ private void CreateNodeCaches() (TypeDesc)helperKey.Target)); }); - _readOnlyDataBlobs = new NodeCache(key => + _readOnlyDataBlobs = new NodeCache(key => { - return new BlobNode(key.Name, ObjectNodeSection.ReadOnlyDataSection, key.Data, key.Alignment); + return new SettableReadOnlyDataBlob(key, ObjectNodeSection.ReadOnlyDataSection); }); _constructedHelpers = new NodeCache(helperId => diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 504f7061d9337..9c416513431dd 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -47,7 +47,6 @@ - @@ -61,6 +60,7 @@ + diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs index 819888a1a87c7..0987481dc0cbd 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs @@ -182,6 +182,14 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe delta = unchecked(targetRVA + (int)_defaultImageBase); break; } + + case RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL: + { + relocationLength = 8; + const uint offsetCorrection = 12; + delta = unchecked(targetRVA - (sourceRVA + offsetCorrection)); + break; + } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: {