Skip to content

Commit

Permalink
Support rodata relocations in crossgen2 for ARM32 (#33153)
Browse files Browse the repository at this point in the history
  • Loading branch information
clamp03 authored Mar 6, 2020
1 parent e61e3d7 commit 790a8d3
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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<Relocation>(), _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
}
}

85 changes: 60 additions & 25 deletions src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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) ?
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -321,7 +339,8 @@ private void CompileMethodCleanup()
_roData = null;
_roDataBlob = null;

_relocs = new ArrayBuilder<Relocation>();
_codeRelocs = new ArrayBuilder<Relocation>();
_roDataRelocs = new ArrayBuilder<Relocation>();

_numFrameInfos = 0;
_usedFrameInfos = 0;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -2611,7 +2630,9 @@ private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO
{
}

private ArrayBuilder<Relocation> _relocs;
private ArrayBuilder<Relocation> _codeRelocs;
private ArrayBuilder<Relocation> _roDataRelocs;


/// <summary>
/// Various type of block.
Expand Down Expand Up @@ -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<Relocation> 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)
{
Expand Down Expand Up @@ -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<Relocation> sourceBlock = ref findRelocBlock(locationBlock, out length);

int relocDelta;
BlockType targetBlock = findKnownBlock(target, out relocDelta);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ public ISymbolNode ReadyToRunHelperFromTypeLookup(ReadyToRunHelperId id, Object
return _genericReadyToRunHelpersFromType.GetOrAdd(new ReadyToRunGenericHelperKey(id, target, dictionaryOwner));
}

private NodeCache<ReadOnlyDataBlobKey, BlobNode> _readOnlyDataBlobs;
private NodeCache<Utf8String, SettableReadOnlyDataBlob> _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<ReadyToRunGenericHelperKey>
Expand Down Expand Up @@ -131,27 +131,6 @@ public override int GetHashCode()
}
}

private struct ReadOnlyDataBlobKey : IEquatable<ReadOnlyDataBlobKey>
{
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<ModuleAndIntValueKey>
{
public readonly int IntValue;
Expand Down Expand Up @@ -235,9 +214,9 @@ private void CreateNodeCaches()
(TypeDesc)helperKey.Target));
});

_readOnlyDataBlobs = new NodeCache<ReadOnlyDataBlobKey, BlobNode>(key =>
_readOnlyDataBlobs = new NodeCache<Utf8String, SettableReadOnlyDataBlob>(key =>
{
return new BlobNode(key.Name, ObjectNodeSection.ReadOnlyDataSection, key.Data, key.Alignment);
return new SettableReadOnlyDataBlob(key, ObjectNodeSection.ReadOnlyDataSection);
});

_constructedHelpers = new NodeCache<ReadyToRunHelper, Import>(helperId =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
<Compile Include="..\..\Common\Compiler\CompilerTypeSystemContext.Validation.cs" Link="Compiler\CompilerTypeSystemContext.Validation.cs" />
<Compile Include="..\..\Common\Compiler\CoreRTNameMangler.cs" Link="Compiler\CoreRTNameMangler.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\AssemblyStubNode.cs" Link="Compiler\DependencyAnalysis\AssemblyStubNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\BlobNode.cs" Link="Compiler\DependencyAnalysis\BlobNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\CompilerComparer.cs" Link="Compiler\DependencyAnalysis\CompilerComparer.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\EmbeddedDataContainerNode.cs" Link="Compiler\DependencyAnalysis\EmbeddedDataContainerNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\IMethodBodyNode.cs" Link="Compiler\DependencyAnalysis\IMethodBodyNode.cs" />
Expand All @@ -61,6 +60,7 @@
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\ObjectNode.cs" Link="Compiler\DependencyAnalysis\ObjectNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\ObjectNodeSection.cs" Link="Compiler\DependencyAnalysis\ObjectNodeSection.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\Relocation.cs" Link="Compiler\DependencyAnalysis\Relocation.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\SettableReadOnlyDataBlob.cs" Link="Compiler\DependencyAnalysis\SettableReadOnlyDataBlob.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\ShadowConcreteMethodNode.cs" Link="Compiler\DependencyAnalysis\ShadowConcreteMethodNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\SortableDependencyNode.cs" Link="Compiler\DependencyAnalysis\SortableDependencyNode.cs" />
<Compile Include="..\..\Common\Compiler\DependencyAnalysis\Target_ARM64\AddrMode.cs" Link="Compiler\DependencyAnalysis\Target_ARM64\AddrMode.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
{
Expand Down

0 comments on commit 790a8d3

Please sign in to comment.