public Relocation(RelocType relocType, int offset, ISymbolNode target, int delta) { RelocType = relocType; Offset = offset; Target = target; Delta = delta; }
public unsafe static long ReadValue(RelocType relocType, void* location) { switch (relocType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: case RelocType.IMAGE_REL_BASED_HIGHLOW: case RelocType.IMAGE_REL_BASED_REL32: return *(int*)location; case RelocType.IMAGE_REL_BASED_DIR64: return *(long*)location; default: Debug.Fail("Invalid RelocType: " + relocType); return 0; } }
public unsafe static void WriteValue(RelocType relocType, void* location, long value) { switch (relocType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: case RelocType.IMAGE_REL_BASED_HIGHLOW: case RelocType.IMAGE_REL_BASED_REL32: *(int*)location = (int)value; break; case RelocType.IMAGE_REL_BASED_DIR64: *(long*)location = value; break; default: Debug.Fail("Invalid RelocType: " + relocType); break; } }
public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0) { Relocation symbolReloc = new Relocation(); symbolReloc.Target = symbol; symbolReloc.RelocType = relocType; symbolReloc.Offset = offset; symbolReloc.Delta = delta; _relocs.Add(symbolReloc); }
/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: case RelocType.IMAGE_REL_SYMBOL_SIZE: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: { relocationLength = 4; delta = (targetRVA - sourceRVA) >> 12; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A: { relocationLength = 4; delta = targetRVA & 0xfff; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); // Supporting non-zero values for ARM64 would require refactoring this function if (((relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21) || (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A)) && (value != 0)) { throw new NotSupportedException(); } Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }
public void EmitReloc(ISymbolNode symbol, RelocType relocType) { AddRelocAtOffset(symbol, relocType, _data.Count); // And add space for the reloc switch (relocType) { case RelocType.IMAGE_REL_BASED_REL32: EmitInt(0); break; case RelocType.IMAGE_REL_BASED_DIR64: EmitLong(0); break; default: throw new NotImplementedException(); } }
public int EmitSymbolRef(string realSymbolName, int offsetFromSymbolName, bool isFunction, RelocType relocType, int delta = 0) { int symbolStartOffset = _currentObjectData.Count; // Workaround for ObjectWriter's lack of support for IMAGE_REL_BASED_RELPTR32 // https://github.com/dotnet/corert/issues/3278 if (relocType == RelocType.IMAGE_REL_BASED_RELPTR32) { relocType = RelocType.IMAGE_REL_BASED_REL32; delta = checked (delta + sizeof(int)); } EmitBlob(new byte[this._nodeFactory.Target.PointerSize]); if (relocType == RelocType.IMAGE_REL_BASED_REL32) { return(this._nodeFactory.Target.PointerSize); } _currentObjectSymbolRefs.Add(symbolStartOffset, new SymbolRefData(isFunction, realSymbolName, delta)); return(_nodeFactory.Target.PointerSize); }
public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0) { Relocation symbolReloc = new Relocation(relocType, offset, symbol, delta); _relocs.Add(symbolReloc); }
/// <summary> /// Emit the .reloc section based on file relocation information in the individual blocks. /// We rely on the fact that the .reloc section is emitted last so that, by the time /// it's getting serialized, all other sections that may contain relocations have already /// been laid out. /// </summary> private BlobBuilder SerializeRelocationSection(SectionLocation sectionLocation) { // There are 12 bits for the relative offset const int RelocationTypeShift = 12; const int MaxRelativeOffsetInBlock = (1 << RelocationTypeShift) - 1; // Even though the format doesn't dictate it, it seems customary // to align the base RVA's on 4K boundaries. const int BaseRVAAlignment = 1 << RelocationTypeShift; BlobBuilder builder = new BlobBuilder(); int baseRVA = 0; List <ushort> offsetsAndTypes = null; Section relocSection = FindSection(R2RPEBuilder.RelocSectionName); if (relocSection != null) { relocSection.FilePosWhenPlaced = sectionLocation.PointerToRawData; relocSection.RVAWhenPlaced = sectionLocation.RelativeVirtualAddress; builder = relocSection.Content; } // Traverse relocations in all sections in their RVA order // By now, all "normal" sections with relocations should already have been laid out foreach (Section section in _sections.OrderBy((sec) => sec.RVAWhenPlaced)) { foreach (PlacedObjectData placedObjectData in section.PlacedObjectDataToRelocate) { for (int relocIndex = 0; relocIndex < placedObjectData.Relocs.Length; relocIndex++) { RelocType relocType = placedObjectData.Relocs[relocIndex].RelocType; RelocType fileRelocType = Relocation.GetFileRelocationType(relocType); if (fileRelocType != RelocType.IMAGE_REL_BASED_ABSOLUTE) { int relocationRVA = section.RVAWhenPlaced + placedObjectData.Offset + placedObjectData.Relocs[relocIndex].Offset; if (offsetsAndTypes != null && relocationRVA - baseRVA > MaxRelativeOffsetInBlock) { // Need to flush relocation block as the current RVA is too far from base RVA FlushRelocationBlock(builder, baseRVA, offsetsAndTypes); offsetsAndTypes = null; } if (offsetsAndTypes == null) { // Create new relocation block baseRVA = relocationRVA & -BaseRVAAlignment; offsetsAndTypes = new List <ushort>(); } ushort offsetAndType = (ushort)(((ushort)fileRelocType << RelocationTypeShift) | (relocationRVA - baseRVA)); offsetsAndTypes.Add(offsetAndType); } } } } if (offsetsAndTypes != null) { FlushRelocationBlock(builder, baseRVA, offsetsAndTypes); } if (builder.Count != 0) { _relocationDirectoryEntry = new DirectoryEntry(sectionLocation.RelativeVirtualAddress, builder.Count); } return(builder); }
private static extern int EmitSymbolRef(IntPtr objWriter, byte[] symbolName, RelocType relocType, int delta);
/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA, int filePosWhenPlaced) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: case RelocType.IMAGE_REL_SYMBOL_SIZE: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; 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: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: { relocationLength = 4; int sourcePageRVA = sourceRVA & ~0xfff; // Page delta always fits in 21 bits as long as we use 4-byte RVAs delta = ((targetRVA - sourcePageRVA) >> 12) & 0x1f_ffff; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A: { relocationLength = 4; delta = targetRVA & 0xfff; break; } case RelocType.IMAGE_REL_FILE_ABSOLUTE: { relocationLength = 4; delta = filePosWhenPlaced; break; } case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC: case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR: { relocationLength = 8; delta = targetRVA - sourceRVA; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); // Supporting non-zero values for ARM64 would require refactoring this function if (((relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21) || (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_PC) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR) ) && (value != 0)) { throw new NotSupportedException(); } Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }
// Returns size of the emitted symbol reference public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType) { string targetName = GetSymbolToEmitForTargetPlatform(target.MangledName); return(EmitSymbolRef(targetName, relocType, delta)); }
/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }
public int EmitSymbolRef(string symbolName, RelocType relocType, int delta = 0) { return(EmitSymbolRef(_nativeObjectWriter, symbolName, relocType, delta)); }
// Returns size of the emitted symbol reference public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType) { _sb.Clear(); AppendExternCPrefix(_sb); target.AppendMangledName(NodeFactory.NameMangler, _sb); return EmitSymbolRef(_sb, relocType, delta); }
public int EmitSymbolRef(Utf8StringBuilder symbolName, RelocType relocType, int delta = 0) { return EmitSymbolRef(_nativeObjectWriter, symbolName.Append('\0').UnderlyingArray, relocType, delta); }
public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) { _builder.EmitReloc(symbol, relocType, delta); }
public Relocation(RelocType relocType, int offset, ISymbolNode target) { RelocType = relocType; Offset = offset; Target = target; }
/// <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 int EmitSymbolRef(string symbolName, RelocType relocType, int delta = 0) { return EmitSymbolRef(_nativeObjectWriter, symbolName, relocType, delta); }
public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) { _relocs.Add(new Relocation(relocType, _data.Count, symbol)); // And add space for the reloc switch (relocType) { case RelocType.IMAGE_REL_BASED_REL32: case RelocType.IMAGE_REL_BASED_ABSOLUTE: EmitInt(delta); break; case RelocType.IMAGE_REL_BASED_DIR64: EmitLong(delta); break; default: throw new NotImplementedException(); } }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = _ilProvider.GetMethodIL(method); if (methodIL == null) { return; } MethodCode methodCode; try { if (_skipJitList.Contains(new TypeAndMethod(method.OwningType.Name, method.Name))) { throw new NotImplementedException("SkipJIT"); } methodCode = _corInfo.CompileMethod(method); if (methodCode.Relocs != null) { if (methodCode.Relocs.Any(r => r.Target is FieldDesc)) { // We only support FieldDesc for InitializeArray intrinsic right now. throw new NotImplementedException("RuntimeFieldHandle is not implemented"); } } } catch (Exception e) { Log.WriteLine("*** " + e.Message + " (" + method + ")"); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } ObjectDataBuilder objData = new ObjectDataBuilder(); objData.Alignment = _nodeFactory.Target.MinimumFunctionAlignment; objData.EmitBytes(methodCode.Code); objData.DefinedSymbols.Add(methodCodeNodeNeedingCode); BlobNode readOnlyDataBlob = null; if (methodCode.ROData != null) { readOnlyDataBlob = _nodeFactory.ReadOnlyDataBlob( "__readonlydata_" + _nameMangler.GetMangledMethodName(method), methodCode.ROData, methodCode.RODataAlignment); } if (methodCode.Relocs != null) { for (int i = 0; i < methodCode.Relocs.Length; i++) { // TODO: Arbitrary relocs if (methodCode.Relocs[i].Block != BlockType.Code) { throw new NotImplementedException(); } int offset = methodCode.Relocs[i].Offset; int delta = methodCode.Relocs[i].Delta; RelocType relocType = (RelocType)methodCode.Relocs[i].RelocType; ISymbolNode targetNode; object target = methodCode.Relocs[i].Target; if (target is MethodDesc) { targetNode = _nodeFactory.MethodEntrypoint((MethodDesc)target); } else if (target is ReadyToRunHelper) { targetNode = _nodeFactory.ReadyToRunHelper((ReadyToRunHelper)target); } else if (target is JitHelper) { targetNode = _nodeFactory.ExternSymbol(((JitHelper)target).MangledName); } else if (target is string) { targetNode = _nodeFactory.StringIndirection((string)target); } else if (target is TypeDesc) { targetNode = _nodeFactory.NecessaryTypeSymbol((TypeDesc)target); } else if (target is RvaFieldData) { var rvaFieldData = (RvaFieldData)target; targetNode = _nodeFactory.ReadOnlyDataBlob(rvaFieldData.MangledName, rvaFieldData.Data, _typeSystemContext.Target.PointerSize); } else if (target is BlockRelativeTarget) { var blockRelativeTarget = (BlockRelativeTarget)target; // TODO: Arbitrary block relative relocs if (blockRelativeTarget.Block != BlockType.ROData) { throw new NotImplementedException(); } targetNode = readOnlyDataBlob; } else { // TODO: throw new NotImplementedException(); } objData.AddRelocAtOffset(targetNode, relocType, offset, delta); } } // TODO: ColdCode if (methodCode.ColdCode != null) { throw new NotImplementedException(); } methodCodeNodeNeedingCode.SetCode(objData.ToObjectData()); methodCodeNodeNeedingCode.InitializeFrameInfos(methodCode.FrameInfos); methodCodeNodeNeedingCode.InitializeDebugLocInfos(methodCode.DebugLocInfos); } }
public int EmitSymbolRef(Utf8StringBuilder symbolName, RelocType relocType, int delta = 0) { return(EmitSymbolRef(_nativeObjectWriter, symbolName.Append('\0').UnderlyingArray, relocType, delta)); }
private static extern int EmitSymbolRef(IntPtr objWriter, string symbolName, RelocType relocType, int delta);
public void AddRelocation(MapFileNode node, RelocType relocType) { node.AddRelocation(); _relocCounts.TryGetValue(relocType, out int relocTypeCount); _relocCounts[relocType] = relocTypeCount + 1; }
// Returns size of the emitted symbol reference public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType) { string targetName = GetSymbolToEmitForTargetPlatform(target.MangledName); return EmitSymbolRef(targetName, relocType, delta); }
// IsDirectCallOrJump reports whether r is a relocation for a direct // call or a direct jump. public static bool IsDirectCallOrJump(this RelocType r) { return(r.IsDirectCall() || r.IsDirectJump()); }