brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.6 KiB · 79b558e Raw
432 lines · c
1//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H10#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H11 12#include "../RuntimeDyldMachO.h"13 14#define DEBUG_TYPE "dyld"15 16namespace llvm {17 18class RuntimeDyldMachOARM19    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {20private:21  typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;22 23public:24 25  typedef uint32_t TargetPtrT;26 27  RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,28                      JITSymbolResolver &Resolver)29    : RuntimeDyldMachOCRTPBase(MM, Resolver) {}30 31  unsigned getMaxStubSize() const override { return 8; }32 33  Align getStubAlignment() override { return Align(4); }34 35  Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {36    auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);37    if (!Flags)38      return Flags.takeError();39    Flags->getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR);40    return Flags;41  }42 43  uint64_t modifyAddressBasedOnFlags(uint64_t Addr,44                                     JITSymbolFlags Flags) const override {45    if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb)46      Addr |= 0x1;47    return Addr;48  }49 50  bool isAddrTargetThumb(unsigned SectionID, uint64_t Offset) {51    auto TargetObjAddr = Sections[SectionID].getObjAddress() + Offset;52    for (auto &KV : GlobalSymbolTable) {53      auto &Entry = KV.second;54      auto SymbolObjAddr =55          Sections[Entry.getSectionID()].getObjAddress() + Entry.getOffset();56      if (TargetObjAddr == SymbolObjAddr)57        return (Entry.getFlags().getTargetFlags() & ARMJITSymbolFlags::Thumb);58    }59    return false;60  }61 62  Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {63    const SectionEntry &Section = Sections[RE.SectionID];64    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);65 66    switch (RE.RelType) {67      default:68        return memcpyAddend(RE);69      case MachO::ARM_RELOC_BR24: {70        uint32_t Temp = readBytesUnaligned(LocalAddress, 4);71        Temp &= 0x00ffffff; // Mask out the opcode.72        // Now we've got the shifted immediate, shift by 2, sign extend and ret.73        return SignExtend32<26>(Temp << 2);74      }75 76      case MachO::ARM_THUMB_RELOC_BR22: {77        // This is a pair of instructions whose operands combine to provide 2278        // bits of displacement:79        // Encoding for high bits 1111 0XXX XXXX XXXX80        // Encoding for low bits  1111 1XXX XXXX XXXX81        uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);82        if ((HighInsn & 0xf800) != 0xf000)83          return make_error<StringError>("Unrecognized thumb branch encoding "84                                         "(BR22 high bits)",85                                         inconvertibleErrorCode());86 87        uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);88        if ((LowInsn & 0xf800) != 0xf800)89          return make_error<StringError>("Unrecognized thumb branch encoding "90                                         "(BR22 low bits)",91                                         inconvertibleErrorCode());92 93        return SignExtend64<23>(((HighInsn & 0x7ff) << 12) |94                                ((LowInsn & 0x7ff) << 1));95      }96    }97  }98 99  Expected<relocation_iterator>100  processRelocationRef(unsigned SectionID, relocation_iterator RelI,101                       const ObjectFile &BaseObjT,102                       ObjSectionToIDMap &ObjSectionToID,103                       StubMap &Stubs) override {104    const MachOObjectFile &Obj =105        static_cast<const MachOObjectFile &>(BaseObjT);106    MachO::any_relocation_info RelInfo =107        Obj.getRelocation(RelI->getRawDataRefImpl());108    uint32_t RelType = Obj.getAnyRelocationType(RelInfo);109 110    // Set to true for thumb functions in this (or previous) TUs.111    // Will be used to set the TargetIsThumbFunc member on the relocation entry.112    bool TargetIsLocalThumbFunc = false;113    if (Obj.getPlainRelocationExternal(RelInfo)) {114      auto Symbol = RelI->getSymbol();115      StringRef TargetName;116      if (auto TargetNameOrErr = Symbol->getName())117        TargetName = *TargetNameOrErr;118      else119        return TargetNameOrErr.takeError();120 121      // If the target is external but the value doesn't have a name then we've122      // converted the value to a section/offset pair, but we still need to set123      // the IsTargetThumbFunc bit, so look the value up in the globla symbol table.124      auto EntryItr = GlobalSymbolTable.find(TargetName);125      if (EntryItr != GlobalSymbolTable.end()) {126        TargetIsLocalThumbFunc =127          EntryItr->second.getFlags().getTargetFlags() &128          ARMJITSymbolFlags::Thumb;129      }130    }131 132    if (Obj.isRelocationScattered(RelInfo)) {133      if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)134        return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,135                                             ObjSectionToID);136      else if (RelType == MachO::GENERIC_RELOC_VANILLA)137        return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,138                                       TargetIsLocalThumbFunc);139      else140        return ++RelI;141    }142 143    // Validate the relocation type.144    switch (RelType) {145    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);146    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);147    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);148    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);149    UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);150    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);151    default:152      if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)153        return make_error<RuntimeDyldError>(("MachO ARM relocation type " +154                                             Twine(RelType) +155                                             " is out of range").str());156      break;157    }158 159    RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));160    if (auto AddendOrErr = decodeAddend(RE))161      RE.Addend = *AddendOrErr;162    else163      return AddendOrErr.takeError();164    RE.IsTargetThumbFunc = TargetIsLocalThumbFunc;165 166    RelocationValueRef Value;167    if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))168      Value = *ValueOrErr;169    else170      return ValueOrErr.takeError();171 172    // If this is a branch from a thumb function (BR22) then make sure we mark173    // the value as being a thumb stub: we don't want to mix it up with an ARM174    // stub targeting the same function.175    if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)176      Value.IsStubThumb = true;177 178    if (RE.IsPCRel)179      makeValueAddendPCRel(Value, RelI,180                           (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);181 182    // If this is a non-external branch target check whether Value points to a183    // thumb func.184    if (!Value.SymbolName && (RelType == MachO::ARM_RELOC_BR24 ||185                              RelType == MachO::ARM_THUMB_RELOC_BR22))186      RE.IsTargetThumbFunc = isAddrTargetThumb(Value.SectionID, Value.Offset);187 188    if (RE.RelType == MachO::ARM_RELOC_BR24 ||189        RE.RelType == MachO::ARM_THUMB_RELOC_BR22)190      processBranchRelocation(RE, Value, Stubs);191    else {192      RE.Addend = Value.Offset;193      if (Value.SymbolName)194        addRelocationForSymbol(RE, Value.SymbolName);195      else196        addRelocationForSection(RE, Value.SectionID);197    }198 199    return ++RelI;200  }201 202  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {203    LLVM_DEBUG(dumpRelocationToResolve(RE, Value));204    const SectionEntry &Section = Sections[RE.SectionID];205    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);206 207    // If the relocation is PC-relative, the value to be encoded is the208    // pointer difference.209    if (RE.IsPCRel) {210      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);211      Value -= FinalAddress;212      // ARM PCRel relocations have an effective-PC offset of two instructions213      // (four bytes in Thumb mode, 8 bytes in ARM mode).214      Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;215    }216 217    switch (RE.RelType) {218    case MachO::ARM_THUMB_RELOC_BR22: {219      Value += RE.Addend;220      uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);221      assert((HighInsn & 0xf800) == 0xf000 &&222             "Unrecognized thumb branch encoding (BR22 high bits)");223      HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff);224 225      uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);226      assert((LowInsn & 0xf800) == 0xf800 &&227             "Unrecognized thumb branch encoding (BR22 low bits)");228      LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff);229 230      writeBytesUnaligned(HighInsn, LocalAddress, 2);231      writeBytesUnaligned(LowInsn, LocalAddress + 2, 2);232      break;233    }234 235    case MachO::ARM_RELOC_VANILLA:236      if (RE.IsTargetThumbFunc)237        Value |= 0x01;238      writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);239      break;240    case MachO::ARM_RELOC_BR24: {241      // Mask the value into the target address. We know instructions are242      // 32-bit aligned, so we can do it all at once.243      Value += RE.Addend;244      // The low two bits of the value are not encoded.245      Value >>= 2;246      // Mask the value to 24 bits.247      uint64_t FinalValue = Value & 0xffffff;248      // FIXME: If the destination is a Thumb function (and the instruction249      // is a non-predicated BL instruction), we need to change it to a BLX250      // instruction instead.251 252      // Insert the value into the instruction.253      uint32_t Temp = readBytesUnaligned(LocalAddress, 4);254      writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);255 256      break;257    }258    case MachO::ARM_RELOC_HALF_SECTDIFF: {259      uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();260      uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();261      assert((Value == SectionABase || Value == SectionBBase) &&262             "Unexpected HALFSECTDIFF relocation value.");263      Value = SectionABase - SectionBBase + RE.Addend;264      if (RE.Size & 0x1) // :upper16:265        Value = (Value >> 16);266 267      bool IsThumb = RE.Size & 0x2;268 269      Value &= 0xffff;270 271      uint32_t Insn = readBytesUnaligned(LocalAddress, 4);272 273      if (IsThumb)274        Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) |275               ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) |276               ((Value & 0x00ff) << 16);277      else278        Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);279      writeBytesUnaligned(Insn, LocalAddress, 4);280      break;281    }282 283    default:284      llvm_unreachable("Invalid relocation type");285    }286  }287 288  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,289                       const SectionRef &Section) {290    StringRef Name;291    if (Expected<StringRef> NameOrErr = Section.getName())292      Name = *NameOrErr;293    else294      consumeError(NameOrErr.takeError());295 296    if (Name == "__nl_symbol_ptr")297      return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),298                                                   Section, SectionID);299    return Error::success();300  }301 302private:303 304  void processBranchRelocation(const RelocationEntry &RE,305                               const RelocationValueRef &Value,306                               StubMap &Stubs) {307    // This is an ARM branch relocation, need to use a stub function.308    // Look up for existing stub.309    SectionEntry &Section = Sections[RE.SectionID];310    RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);311    uint8_t *Addr;312    if (i != Stubs.end()) {313      Addr = Section.getAddressWithOffset(i->second);314    } else {315      // Create a new stub function.316      assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");317      Stubs[Value] = Section.getStubOffset();318      uint32_t StubOpcode = 0;319      if (RE.RelType == MachO::ARM_RELOC_BR24)320        StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4]321      else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)322        StubOpcode = 0xf000f8df; // ldr pc, [pc]323      else324        llvm_unreachable("Unrecognized relocation");325      Addr = Section.getAddressWithOffset(Section.getStubOffset());326      writeBytesUnaligned(StubOpcode, Addr, 4);327      uint8_t *StubTargetAddr = Addr + 4;328      RelocationEntry StubRE(329          RE.SectionID, StubTargetAddr - Section.getAddress(),330          MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);331      StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;332      if (Value.SymbolName)333        addRelocationForSymbol(StubRE, Value.SymbolName);334      else335        addRelocationForSection(StubRE, Value.SectionID);336      Section.advanceStubOffset(getMaxStubSize());337    }338    RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,339                             RE.IsPCRel, RE.Size);340    resolveRelocation(TargetRE, (uint64_t)Addr);341  }342 343  Expected<relocation_iterator>344  processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,345                                const ObjectFile &BaseTObj,346                                ObjSectionToIDMap &ObjSectionToID) {347    const MachOObjectFile &MachO =348        static_cast<const MachOObjectFile&>(BaseTObj);349    MachO::any_relocation_info RE =350        MachO.getRelocation(RelI->getRawDataRefImpl());351 352    // For a half-diff relocation the length bits actually record whether this353    // is a movw/movt, and whether this is arm or thumb.354    // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).355    // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).356    unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);357    bool IsThumb = HalfDiffKindBits & 0x2;358 359    SectionEntry &Section = Sections[SectionID];360    uint32_t RelocType = MachO.getAnyRelocationType(RE);361    bool IsPCRel = MachO.getAnyRelocationPCRel(RE);362    uint64_t Offset = RelI->getOffset();363    uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);364    int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.365 366    if (IsThumb)367      Immediate = ((Immediate & 0x0000000f) << 12) |368                  ((Immediate & 0x00000400) << 1) |369                  ((Immediate & 0x70000000) >> 20) |370                  ((Immediate & 0x00ff0000) >> 16);371    else372      Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);373 374    ++RelI;375    MachO::any_relocation_info RE2 =376      MachO.getRelocation(RelI->getRawDataRefImpl());377    uint32_t AddrA = MachO.getScatteredRelocationValue(RE);378    section_iterator SAI = getSectionByAddress(MachO, AddrA);379    assert(SAI != MachO.section_end() && "Can't find section for address A");380    uint64_t SectionABase = SAI->getAddress();381    uint64_t SectionAOffset = AddrA - SectionABase;382    SectionRef SectionA = *SAI;383    bool IsCode = SectionA.isText();384    uint32_t SectionAID = ~0U;385    if (auto SectionAIDOrErr =386          findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))387      SectionAID = *SectionAIDOrErr;388    else389      return SectionAIDOrErr.takeError();390 391    uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);392    section_iterator SBI = getSectionByAddress(MachO, AddrB);393    assert(SBI != MachO.section_end() && "Can't find section for address B");394    uint64_t SectionBBase = SBI->getAddress();395    uint64_t SectionBOffset = AddrB - SectionBBase;396    SectionRef SectionB = *SBI;397    uint32_t SectionBID = ~0U;398    if (auto SectionBIDOrErr =399          findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))400      SectionBID = *SectionBIDOrErr;401    else402      return SectionBIDOrErr.takeError();403 404    uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;405    unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;406    uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));407    int64_t Addend = FullImmVal - (AddrA - AddrB);408 409    // addend = Encoded - Expected410    //        = Encoded - (AddrA - AddrB)411 412    LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA413                      << ", AddrB: " << AddrB << ", Addend: " << Addend414                      << ", SectionA ID: " << SectionAID << ", SectionAOffset: "415                      << SectionAOffset << ", SectionB ID: " << SectionBID416                      << ", SectionBOffset: " << SectionBOffset << "\n");417    RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,418                      SectionAOffset, SectionBID, SectionBOffset, IsPCRel,419                      HalfDiffKindBits);420 421    addRelocationForSection(R, SectionAID);422 423    return ++RelI;424  }425 426};427}428 429#undef DEBUG_TYPE430 431#endif432