diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 29cace15d8cf9b..c8eda17daaa04a 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1173,15 +1173,23 @@ void Compiler::eeAllocMem(AllocMemChunk& codeChunk, for (unsigned i = 0; i < numDataChunks; i++) { - // Increase size of the hot code chunk and store offset in data chunk - AllocMemChunk& codeChunk = chunks.BottomRef(0); + if ((dataChunks[i].flags & CORJIT_ALLOCMEM_HAS_POINTERS_TO_CODE) != 0) + { + // These are always passed to the EE as separate chunks since their relocations need special treatment + chunks.Push(dataChunks[i]); + } + else + { + // Increase size of the hot code chunk and store offset in data chunk + AllocMemChunk& codeChunk = chunks.BottomRef(0); - codeChunk.size = AlignUp(codeChunk.size, dataChunks[i].alignment); - dataChunks[i].block = (uint8_t*)(uintptr_t)codeChunk.size; - dataChunks[i].blockRW = (uint8_t*)(uintptr_t)codeChunk.size; - codeChunk.size += dataChunks[i].size; + codeChunk.size = AlignUp(codeChunk.size, dataChunks[i].alignment); + dataChunks[i].block = (uint8_t*)(uintptr_t)codeChunk.size; + dataChunks[i].blockRW = (uint8_t*)(uintptr_t)codeChunk.size; + codeChunk.size += dataChunks[i].size; - codeChunk.alignment = max(codeChunk.alignment, dataChunks[i].alignment); + codeChunk.alignment = max(codeChunk.alignment, dataChunks[i].alignment); + } } #else @@ -1228,8 +1236,18 @@ void Compiler::eeAllocMem(AllocMemChunk& codeChunk, // Fix up data section pointers. for (unsigned i = 0; i < numDataChunks; i++) { - dataChunks[i].block = codeChunk.block + (size_t)dataChunks[i].block; - dataChunks[i].blockRW = codeChunk.blockRW + (size_t)dataChunks[i].blockRW; + if ((dataChunks[i].flags & CORJIT_ALLOCMEM_HAS_POINTERS_TO_CODE) != 0) + { + // These are always passed to the EE as separate chunks since their relocations need special treatment + dataChunks[i].block = chunks.BottomRef(curDataChunk).block; + dataChunks[i].blockRW = chunks.BottomRef(curDataChunk).blockRW; + curDataChunk++; + } + else + { + dataChunks[i].block = codeChunk.block + (size_t)dataChunks[i].block; + dataChunks[i].blockRW = codeChunk.blockRW + (size_t)dataChunks[i].blockRW; + } } #else diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs index 6532f6c4be1647..0aa3790bf513cd 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs @@ -26,9 +26,8 @@ public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) } #endif - // TODO: (async) This should stay RO everywhere: https://github.com/dotnet/runtime/issues/121871 public override ObjectNodeSection GetSection(NodeFactory factory) - => factory.Target.IsWindows ? ObjectNodeSection.ReadOnlyDataSection : ObjectNodeSection.DataSection; + => ObjectNodeSection.ReadOnlyDataSection; public override bool StaticDependenciesAreComputed => _data != null; diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadWriteDataNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadWriteDataNode.cs new file mode 100644 index 00000000000000..bc2a0a15c3808a --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/MethodReadWriteDataNode.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +using Internal.Text; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public class MethodReadWriteDataNode : ObjectNode, ISymbolDefinitionNode + { + private MethodDesc _owningMethod; + private ObjectData _data; + + public MethodReadWriteDataNode(MethodDesc owningMethod) + { + _owningMethod = owningMethod; + } + +#if !READYTORUN + public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) + { + IMethodNode owningBody = factory.MethodEntrypoint(_owningMethod); + return factory.ObjectInterner.GetDeduplicatedSymbol(factory, owningBody) != owningBody; + } +#endif + + public override ObjectNodeSection GetSection(NodeFactory factory) + => ObjectNodeSection.DataSection; + + public override bool StaticDependenciesAreComputed => _data != null; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append("__readwritedata_"u8).Append(nameMangler.GetMangledMethodName(_owningMethod)); + } + 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 _data; + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + +#if !SUPPORT_JIT + public override int ClassCode => 689723708; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return comparer.Compare(_owningMethod, ((MethodReadWriteDataNode)other)._owningMethod); + } +#endif + } +} diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 49a70a4085a0d8..3c3a947b9fb809 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -427,6 +427,7 @@ private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedin PublishCode(); PublishROData(); + PublishRWData(); return CompilationResult.CompilationComplete; } @@ -599,6 +600,23 @@ private void PublishROData() _roDataBlob.InitializeData(objectData); } + private void PublishRWData() + { + if (_rwDataBlob == null) + { + return; + } + + var relocs = _rwDataRelocs.ToArray(); + Array.Sort(relocs, (x, y) => (x.Offset - y.Offset)); + var objectData = new ObjectNode.ObjectData(_rwData, + relocs, + _rwDataAlignment, + new ISymbolDefinitionNode[] { _rwDataBlob }); + + _rwDataBlob.InitializeData(objectData); + } + private MethodDesc MethodBeingCompiled { get @@ -653,8 +671,12 @@ private void CompileMethodCleanup() _roData = null; _roDataBlob = null; + _rwData = null; + _rwDataBlob = null; + _codeRelocs = default(ArrayBuilder); _roDataRelocs = default(ArrayBuilder); + _rwDataRelocs = default(ArrayBuilder); #if READYTORUN _coldCodeRelocs = default(ArrayBuilder); #endif @@ -3799,6 +3821,10 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI private MethodReadOnlyDataNode _roDataBlob; private int _roDataAlignment; + private byte[] _rwData; + private MethodReadWriteDataNode _rwDataBlob; + private int _rwDataAlignment; + private int _numFrameInfos; private int _usedFrameInfos; private FrameInfo[] _frameInfos; @@ -3819,9 +3845,16 @@ private void allocMem(ref AllocMemArgs args) Span chunks = new Span(args.chunks, checked((int)args.chunksCount)); uint roDataSize = 0; + uint rwDataSize = 0; _codeAlignment = -1; _roDataAlignment = -1; + _rwDataAlignment = -1; + + // ELF/MachO do not support relocations from read-only sections to code sections, so we must put these + // into read-write sections. + bool ChunkNeedsReadWriteSection(in AllocMemChunk chunk) + => (chunk.flags & CorJitAllocMemFlag.CORJIT_ALLOCMEM_HAS_POINTERS_TO_CODE) != 0 && !_compilation.TypeSystemContext.Target.IsWindows; foreach (ref AllocMemChunk chunk in chunks) { @@ -3840,6 +3873,13 @@ private void allocMem(ref AllocMemArgs args) _methodColdCodeNode = new MethodColdCodeNode(MethodBeingCompiled); #endif } + else if (ChunkNeedsReadWriteSection(chunk)) + { + // For ELF/MachO we need to put data containing relocations into .text into a RW section + rwDataSize = (uint)((int)rwDataSize).AlignUp((int)chunk.alignment); + rwDataSize += chunk.size; + _rwDataAlignment = Math.Max(_rwDataAlignment, (int)chunk.alignment); + } else { roDataSize = (uint)((int)roDataSize).AlignUp((int)chunk.alignment); @@ -3862,6 +3902,11 @@ private void allocMem(ref AllocMemArgs args) continue; } + if (ChunkNeedsReadWriteSection(chunk)) + { + continue; + } + offset = offset.AlignUp((int)chunk.alignment); chunk.block = roDataBlock + offset; chunk.blockRW = chunk.block; @@ -3871,6 +3916,31 @@ private void allocMem(ref AllocMemArgs args) Debug.Assert(offset <= roDataSize); } + if (rwDataSize != 0) + { + _rwData = new byte[rwDataSize]; + _rwDataBlob = new MethodReadWriteDataNode(MethodBeingCompiled); + byte* rwDataBlock = (byte*)GetPin(_rwData); + int offset = 0; + + foreach (ref AllocMemChunk chunk in chunks) + { + if ((chunk.flags & (CorJitAllocMemFlag.CORJIT_ALLOCMEM_HOT_CODE | CorJitAllocMemFlag.CORJIT_ALLOCMEM_COLD_CODE)) != 0) + { + continue; + } + if (ChunkNeedsReadWriteSection(chunk)) + { + offset = offset.AlignUp((int)chunk.alignment); + chunk.block = rwDataBlock + offset; + chunk.blockRW = chunk.block; + offset += (int)chunk.size; + } + } + + Debug.Assert(offset <= rwDataSize); + } + if (_numFrameInfos > 0) { _frameInfos = new FrameInfo[_numFrameInfos]; @@ -3982,6 +4052,7 @@ private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO private ArrayBuilder _codeRelocs; private ArrayBuilder _roDataRelocs; + private ArrayBuilder _rwDataRelocs; #if READYTORUN private ArrayBuilder _coldCodeRelocs; #endif @@ -3999,8 +4070,10 @@ public enum BlockType : sbyte ColdCode = 1, /// Read-only data. ROData = 2, + /// Read-write data. + RWData = 3, /// Instrumented Block Count Data - BBCounts = 3 + BBCounts = 4 } private BlockType findKnownBlock(void* location, out int offset) @@ -4038,6 +4111,18 @@ private BlockType findKnownBlock(void* location, out int offset) } } + if (_rwData != null) + { + fixed (byte* pRWData = _rwData) + { + if (pRWData <= (byte*)location && (byte*)location < pRWData + _rwData.Length) + { + offset = (int)((byte*)location - pRWData); + return BlockType.RWData; + } + } + } + { BlockType retBlockType = BlockType.Unknown; offset = 0; @@ -4062,6 +4147,9 @@ private ref ArrayBuilder findRelocBlock(BlockType blockType, out int case BlockType.ROData: length = _roData.Length; return ref _roDataRelocs; + case BlockType.RWData: + length = _rwData.Length; + return ref _rwDataRelocs; #if READYTORUN case BlockType.ColdCode: length = _coldCode.Length; @@ -4132,6 +4220,10 @@ private void recordRelocation(void* location, void* locationRW, void* target, Co relocTarget = _roDataBlob; break; + case BlockType.RWData: + relocTarget = _rwDataBlob; + break; + #if READYTORUN case BlockType.BBCounts: relocTarget = null; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index c47166526d0b65..c0101c45f45eef 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -304,6 +304,7 @@ + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 4e460cb2b14544..df41ef67a7fef5 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -90,6 +90,7 @@ + diff --git a/src/tests/async/Directory.Build.targets b/src/tests/async/Directory.Build.targets index f2d39cb6d975ff..3467f16c2be66f 100644 --- a/src/tests/async/Directory.Build.targets +++ b/src/tests/async/Directory.Build.targets @@ -3,11 +3,5 @@ true - - - - true - - diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/UnitTests.csproj b/src/tests/nativeaot/SmokeTests/UnitTests/UnitTests.csproj index 8fee28a032ab7f..2727cac733f6eb 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/UnitTests.csproj +++ b/src/tests/nativeaot/SmokeTests/UnitTests/UnitTests.csproj @@ -13,11 +13,7 @@ order.txt true - - - - $(Features);runtime-async=on