LCOV - code coverage report
Current view: top level - lib/ExecutionEngine/RuntimeDyld/Targets - RuntimeDyldMachOARM.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 160 183 87.4 %
Date: 2018-06-17 00:07:59 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13