Home | History | Annotate | Download | only in Targets
      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 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                       RuntimeDyld::SymbolResolver &Resolver)
     31     : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
     32 
     33   unsigned getMaxStubSize() override { return 8; }
     34 
     35   unsigned getStubAlignment() override { return 4; }
     36 
     37   int64_t decodeAddend(const RelocationEntry &RE) const {
     38     const SectionEntry &Section = Sections[RE.SectionID];
     39     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
     40 
     41     switch (RE.RelType) {
     42       default:
     43         return memcpyAddend(RE);
     44       case MachO::ARM_RELOC_BR24: {
     45         uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
     46         Temp &= 0x00ffffff; // Mask out the opcode.
     47         // Now we've got the shifted immediate, shift by 2, sign extend and ret.
     48         return SignExtend32<26>(Temp << 2);
     49       }
     50     }
     51   }
     52 
     53   Expected<relocation_iterator>
     54   processRelocationRef(unsigned SectionID, relocation_iterator RelI,
     55                        const ObjectFile &BaseObjT,
     56                        ObjSectionToIDMap &ObjSectionToID,
     57                        StubMap &Stubs) override {
     58     const MachOObjectFile &Obj =
     59         static_cast<const MachOObjectFile &>(BaseObjT);
     60     MachO::any_relocation_info RelInfo =
     61         Obj.getRelocation(RelI->getRawDataRefImpl());
     62     uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
     63 
     64     if (Obj.isRelocationScattered(RelInfo)) {
     65       if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
     66         return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
     67                                              ObjSectionToID);
     68       else if (RelType == MachO::GENERIC_RELOC_VANILLA)
     69         return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
     70       else
     71         return ++RelI;
     72     }
     73 
     74     // Sanity check relocation type.
     75     switch (RelType) {
     76     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);
     77     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
     78     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
     79     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
     80     UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_RELOC_BR22);
     81     UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);
     82     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
     83     default:
     84       if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)
     85         return make_error<RuntimeDyldError>(("MachO ARM relocation type " +
     86                                              Twine(RelType) +
     87                                              " is out of range").str());
     88       break;
     89     }
     90 
     91     RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
     92     RE.Addend = decodeAddend(RE);
     93     RelocationValueRef Value;
     94     if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
     95       Value = *ValueOrErr;
     96     else
     97       return ValueOrErr.takeError();
     98 
     99     if (RE.IsPCRel)
    100       makeValueAddendPCRel(Value, RelI, 8);
    101 
    102     if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
    103       processBranchRelocation(RE, Value, Stubs);
    104     else {
    105       RE.Addend = Value.Offset;
    106       if (Value.SymbolName)
    107         addRelocationForSymbol(RE, Value.SymbolName);
    108       else
    109         addRelocationForSection(RE, Value.SectionID);
    110     }
    111 
    112     return ++RelI;
    113   }
    114 
    115   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
    116     DEBUG(dumpRelocationToResolve(RE, Value));
    117     const SectionEntry &Section = Sections[RE.SectionID];
    118     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
    119 
    120     // If the relocation is PC-relative, the value to be encoded is the
    121     // pointer difference.
    122     if (RE.IsPCRel) {
    123       uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
    124       Value -= FinalAddress;
    125       // ARM PCRel relocations have an effective-PC offset of two instructions
    126       // (four bytes in Thumb mode, 8 bytes in ARM mode).
    127       // FIXME: For now, assume ARM mode.
    128       Value -= 8;
    129     }
    130 
    131     switch (RE.RelType) {
    132     case MachO::ARM_RELOC_VANILLA:
    133       writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
    134       break;
    135     case MachO::ARM_RELOC_BR24: {
    136       // Mask the value into the target address. We know instructions are
    137       // 32-bit aligned, so we can do it all at once.
    138       Value += RE.Addend;
    139       // The low two bits of the value are not encoded.
    140       Value >>= 2;
    141       // Mask the value to 24 bits.
    142       uint64_t FinalValue = Value & 0xffffff;
    143       // FIXME: If the destination is a Thumb function (and the instruction
    144       // is a non-predicated BL instruction), we need to change it to a BLX
    145       // instruction instead.
    146 
    147       // Insert the value into the instruction.
    148       uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
    149       writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
    150 
    151       break;
    152     }
    153     case MachO::ARM_RELOC_HALF_SECTDIFF: {
    154       uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
    155       uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
    156       assert((Value == SectionABase || Value == SectionBBase) &&
    157              "Unexpected HALFSECTDIFF relocation value.");
    158       Value = SectionABase - SectionBBase + RE.Addend;
    159       if (RE.Size & 0x1) // :upper16:
    160         Value = (Value >> 16);
    161       Value &= 0xffff;
    162 
    163       uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
    164       Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
    165       writeBytesUnaligned(Insn, LocalAddress, 4);
    166       break;
    167     }
    168 
    169     default:
    170       llvm_unreachable("Invalid relocation type");
    171     }
    172   }
    173 
    174   Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
    175                        const SectionRef &Section) {
    176     StringRef Name;
    177     Section.getName(Name);
    178 
    179     if (Name == "__nl_symbol_ptr")
    180       return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
    181                                                    Section, SectionID);
    182     return Error::success();
    183   }
    184 
    185 private:
    186 
    187   void processBranchRelocation(const RelocationEntry &RE,
    188                                const RelocationValueRef &Value,
    189                                StubMap &Stubs) {
    190     // This is an ARM branch relocation, need to use a stub function.
    191     // Look up for existing stub.
    192     SectionEntry &Section = Sections[RE.SectionID];
    193     RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
    194     uint8_t *Addr;
    195     if (i != Stubs.end()) {
    196       Addr = Section.getAddressWithOffset(i->second);
    197     } else {
    198       // Create a new stub function.
    199       Stubs[Value] = Section.getStubOffset();
    200       uint8_t *StubTargetAddr = createStubFunction(
    201           Section.getAddressWithOffset(Section.getStubOffset()));
    202       RelocationEntry StubRE(
    203           RE.SectionID, StubTargetAddr - Section.getAddress(),
    204           MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
    205       if (Value.SymbolName)
    206         addRelocationForSymbol(StubRE, Value.SymbolName);
    207       else
    208         addRelocationForSection(StubRE, Value.SectionID);
    209       Addr = Section.getAddressWithOffset(Section.getStubOffset());
    210       Section.advanceStubOffset(getMaxStubSize());
    211     }
    212     RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
    213                              RE.IsPCRel, RE.Size);
    214     resolveRelocation(TargetRE, (uint64_t)Addr);
    215   }
    216 
    217   Expected<relocation_iterator>
    218   processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
    219                                 const ObjectFile &BaseTObj,
    220                                 ObjSectionToIDMap &ObjSectionToID) {
    221     const MachOObjectFile &MachO =
    222         static_cast<const MachOObjectFile&>(BaseTObj);
    223     MachO::any_relocation_info RE =
    224         MachO.getRelocation(RelI->getRawDataRefImpl());
    225 
    226 
    227     // For a half-diff relocation the length bits actually record whether this
    228     // is a movw/movt, and whether this is arm or thumb.
    229     // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
    230     // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
    231     unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
    232     if (HalfDiffKindBits & 0x2)
    233       llvm_unreachable("Thumb not yet supported.");
    234 
    235     SectionEntry &Section = Sections[SectionID];
    236     uint32_t RelocType = MachO.getAnyRelocationType(RE);
    237     bool IsPCRel = MachO.getAnyRelocationPCRel(RE);
    238     uint64_t Offset = RelI->getOffset();
    239     uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
    240     int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
    241     Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
    242 
    243     ++RelI;
    244     MachO::any_relocation_info RE2 =
    245       MachO.getRelocation(RelI->getRawDataRefImpl());
    246     uint32_t AddrA = MachO.getScatteredRelocationValue(RE);
    247     section_iterator SAI = getSectionByAddress(MachO, AddrA);
    248     assert(SAI != MachO.section_end() && "Can't find section for address A");
    249     uint64_t SectionABase = SAI->getAddress();
    250     uint64_t SectionAOffset = AddrA - SectionABase;
    251     SectionRef SectionA = *SAI;
    252     bool IsCode = SectionA.isText();
    253     uint32_t SectionAID = ~0U;
    254     if (auto SectionAIDOrErr =
    255           findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))
    256       SectionAID = *SectionAIDOrErr;
    257     else
    258       return SectionAIDOrErr.takeError();
    259 
    260     uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);
    261     section_iterator SBI = getSectionByAddress(MachO, AddrB);
    262     assert(SBI != MachO.section_end() && "Can't find section for address B");
    263     uint64_t SectionBBase = SBI->getAddress();
    264     uint64_t SectionBOffset = AddrB - SectionBBase;
    265     SectionRef SectionB = *SBI;
    266     uint32_t SectionBID = ~0U;
    267     if (auto SectionBIDOrErr =
    268           findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))
    269       SectionBID = *SectionBIDOrErr;
    270     else
    271       return SectionBIDOrErr.takeError();
    272 
    273     uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;
    274     unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
    275     uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
    276     int64_t Addend = FullImmVal - (AddrA - AddrB);
    277 
    278     // addend = Encoded - Expected
    279     //        = Encoded - (AddrA - AddrB)
    280 
    281     DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
    282                  << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
    283                  << ", SectionAOffset: " << SectionAOffset
    284                  << ", SectionB ID: " << SectionBID
    285                  << ", SectionBOffset: " << SectionBOffset << "\n");
    286     RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
    287                       SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
    288                       HalfDiffKindBits);
    289 
    290     addRelocationForSection(R, SectionAID);
    291     addRelocationForSection(R, SectionBID);
    292 
    293     return ++RelI;
    294   }
    295 
    296 };
    297 }
    298 
    299 #undef DEBUG_TYPE
    300 
    301 #endif
    302