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

Generated by: LCOV version 1.13