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