LLVM API Documentation

RuntimeDyldMachOARM.h
Go to the documentation of this file.
00001 //===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
00011 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
00012 
00013 #include "../RuntimeDyldMachO.h"
00014 
00015 #define DEBUG_TYPE "dyld"
00016 
00017 namespace llvm {
00018 
00019 class RuntimeDyldMachOARM
00020     : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
00021 private:
00022   typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
00023 
00024 public:
00025 
00026   typedef uint32_t TargetPtrT;
00027 
00028   RuntimeDyldMachOARM(RTDyldMemoryManager *MM) : RuntimeDyldMachOCRTPBase(MM) {}
00029 
00030   unsigned getMaxStubSize() override { return 8; }
00031 
00032   unsigned getStubAlignment() override { return 4; }
00033 
00034   int64_t decodeAddend(const RelocationEntry &RE) const {
00035     const SectionEntry &Section = Sections[RE.SectionID];
00036     uint8_t *LocalAddress = Section.Address + RE.Offset;
00037 
00038     switch (RE.RelType) {
00039       default:
00040         return memcpyAddend(RE);
00041       case MachO::ARM_RELOC_BR24: {
00042         uint32_t Temp;
00043         memcpy(&Temp, LocalAddress, 4);
00044         Temp &= 0x00ffffff; // Mask out the opcode.
00045         // Now we've got the shifted immediate, shift by 2, sign extend and ret.
00046         return SignExtend32<26>(Temp << 2);
00047       }
00048     }
00049   }
00050 
00051   relocation_iterator
00052   processRelocationRef(unsigned SectionID, relocation_iterator RelI,
00053                        ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
00054                        const SymbolTableMap &Symbols, StubMap &Stubs) override {
00055     const MachOObjectFile &Obj =
00056         static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
00057     MachO::any_relocation_info RelInfo =
00058         Obj.getRelocation(RelI->getRawDataRefImpl());
00059     uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
00060 
00061     if (Obj.isRelocationScattered(RelInfo)) {
00062       if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
00063         return processHALFSECTDIFFRelocation(SectionID, RelI, ObjImg,
00064                                              ObjSectionToID);
00065       else
00066         return ++++RelI;
00067     }
00068 
00069     RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI));
00070     RE.Addend = decodeAddend(RE);
00071     RelocationValueRef Value(
00072         getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
00073 
00074     if (RE.IsPCRel)
00075       makeValueAddendPCRel(Value, ObjImg, RelI, 8);
00076 
00077     if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
00078       processBranchRelocation(RE, Value, Stubs);
00079     else {
00080       RE.Addend = Value.Offset;
00081       if (Value.SymbolName)
00082         addRelocationForSymbol(RE, Value.SymbolName);
00083       else
00084         addRelocationForSection(RE, Value.SectionID);
00085     }
00086 
00087     return ++RelI;
00088   }
00089 
00090   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
00091     DEBUG(dumpRelocationToResolve(RE, Value));
00092     const SectionEntry &Section = Sections[RE.SectionID];
00093     uint8_t *LocalAddress = Section.Address + RE.Offset;
00094 
00095     // If the relocation is PC-relative, the value to be encoded is the
00096     // pointer difference.
00097     if (RE.IsPCRel) {
00098       uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
00099       Value -= FinalAddress;
00100       // ARM PCRel relocations have an effective-PC offset of two instructions
00101       // (four bytes in Thumb mode, 8 bytes in ARM mode).
00102       // FIXME: For now, assume ARM mode.
00103       Value -= 8;
00104     }
00105 
00106     switch (RE.RelType) {
00107     default:
00108       llvm_unreachable("Invalid relocation type!");
00109     case MachO::ARM_RELOC_VANILLA:
00110       writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
00111       break;
00112     case MachO::ARM_RELOC_BR24: {
00113       // Mask the value into the target address. We know instructions are
00114       // 32-bit aligned, so we can do it all at once.
00115       uint32_t *p = (uint32_t *)LocalAddress;
00116       Value += RE.Addend;
00117       // The low two bits of the value are not encoded.
00118       Value >>= 2;
00119       // Mask the value to 24 bits.
00120       uint64_t FinalValue = Value & 0xffffff;
00121       // FIXME: If the destination is a Thumb function (and the instruction
00122       // is a non-predicated BL instruction), we need to change it to a BLX
00123       // instruction instead.
00124 
00125       // Insert the value into the instruction.
00126       *p = (*p & ~0xffffff) | FinalValue;
00127       break;
00128     }
00129     case MachO::ARM_RELOC_HALF_SECTDIFF: {
00130       uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
00131       uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
00132       assert((Value == SectionABase || Value == SectionBBase) &&
00133              "Unexpected HALFSECTDIFF relocation value.");
00134       Value = SectionABase - SectionBBase + RE.Addend;
00135       if (RE.Size & 0x1) // :upper16:
00136         Value = (Value >> 16);
00137       Value &= 0xffff;
00138 
00139       uint32_t Insn;
00140       memcpy(&Insn, LocalAddress, 4);
00141       Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
00142       memcpy(LocalAddress, &Insn, 4);
00143       break;
00144     }
00145 
00146     case MachO::ARM_THUMB_RELOC_BR22:
00147     case MachO::ARM_THUMB_32BIT_BRANCH:
00148     case MachO::ARM_RELOC_HALF:
00149     case MachO::ARM_RELOC_PAIR:
00150     case MachO::ARM_RELOC_SECTDIFF:
00151     case MachO::ARM_RELOC_LOCAL_SECTDIFF:
00152     case MachO::ARM_RELOC_PB_LA_PTR:
00153       Error("Relocation type not implemented yet!");
00154       return;
00155     }
00156   }
00157 
00158   void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
00159                        const SectionRef &Section) {
00160     StringRef Name;
00161     Section.getName(Name);
00162 
00163     if (Name == "__nl_symbol_ptr")
00164       populateIndirectSymbolPointersSection(
00165                                  cast<MachOObjectFile>(*ObjImg.getObjectFile()),
00166                                  Section, SectionID);
00167   }
00168 
00169 private:
00170 
00171   void processBranchRelocation(const RelocationEntry &RE,
00172                                const RelocationValueRef &Value,
00173                                StubMap &Stubs) {
00174     // This is an ARM branch relocation, need to use a stub function.
00175     // Look up for existing stub.
00176     SectionEntry &Section = Sections[RE.SectionID];
00177     RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
00178     uint8_t *Addr;
00179     if (i != Stubs.end()) {
00180       Addr = Section.Address + i->second;
00181     } else {
00182       // Create a new stub function.
00183       Stubs[Value] = Section.StubOffset;
00184       uint8_t *StubTargetAddr =
00185           createStubFunction(Section.Address + Section.StubOffset);
00186       RelocationEntry StubRE(RE.SectionID, StubTargetAddr - Section.Address,
00187                              MachO::GENERIC_RELOC_VANILLA, Value.Offset, false,
00188                              2);
00189       if (Value.SymbolName)
00190         addRelocationForSymbol(StubRE, Value.SymbolName);
00191       else
00192         addRelocationForSection(StubRE, Value.SectionID);
00193       Addr = Section.Address + Section.StubOffset;
00194       Section.StubOffset += getMaxStubSize();
00195     }
00196     RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
00197                              RE.IsPCRel, RE.Size);
00198     resolveRelocation(TargetRE, (uint64_t)Addr);
00199   }
00200 
00201   relocation_iterator
00202   processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
00203                                 ObjectImage &Obj,
00204                                 ObjSectionToIDMap &ObjSectionToID) {
00205     const MachOObjectFile *MachO =
00206         static_cast<const MachOObjectFile *>(Obj.getObjectFile());
00207     MachO::any_relocation_info RE =
00208         MachO->getRelocation(RelI->getRawDataRefImpl());
00209 
00210 
00211     // For a half-diff relocation the length bits actually record whether this
00212     // is a movw/movt, and whether this is arm or thumb.
00213     // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
00214     // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
00215     unsigned HalfDiffKindBits = MachO->getAnyRelocationLength(RE);
00216     if (HalfDiffKindBits & 0x2)
00217       llvm_unreachable("Thumb not yet supported.");
00218 
00219     SectionEntry &Section = Sections[SectionID];
00220     uint32_t RelocType = MachO->getAnyRelocationType(RE);
00221     bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
00222     uint64_t Offset;
00223     RelI->getOffset(Offset);
00224     uint8_t *LocalAddress = Section.Address + Offset;
00225     int64_t Immediate = 0;
00226     memcpy(&Immediate, LocalAddress, 4); // Copy the whole instruction out.
00227     Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
00228 
00229     ++RelI;
00230     MachO::any_relocation_info RE2 =
00231         MachO->getRelocation(RelI->getRawDataRefImpl());
00232     uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
00233     section_iterator SAI = getSectionByAddress(*MachO, AddrA);
00234     assert(SAI != MachO->section_end() && "Can't find section for address A");
00235     uint64_t SectionABase;
00236     SAI->getAddress(SectionABase);
00237     uint64_t SectionAOffset = AddrA - SectionABase;
00238     SectionRef SectionA = *SAI;
00239     bool IsCode;
00240     SectionA.isText(IsCode);
00241     uint32_t SectionAID =
00242         findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID);
00243 
00244     uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
00245     section_iterator SBI = getSectionByAddress(*MachO, AddrB);
00246     assert(SBI != MachO->section_end() && "Can't find section for address B");
00247     uint64_t SectionBBase;
00248     SBI->getAddress(SectionBBase);
00249     uint64_t SectionBOffset = AddrB - SectionBBase;
00250     SectionRef SectionB = *SBI;
00251     uint32_t SectionBID =
00252         findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID);
00253 
00254     uint32_t OtherHalf = MachO->getAnyRelocationAddress(RE2) & 0xffff;
00255     unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
00256     uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
00257     int64_t Addend = FullImmVal - (AddrA - AddrB);
00258 
00259     // addend = Encoded - Expected
00260     //        = Encoded - (AddrA - AddrB)
00261 
00262     DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
00263                  << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
00264                  << ", SectionAOffset: " << SectionAOffset
00265                  << ", SectionB ID: " << SectionBID
00266                  << ", SectionBOffset: " << SectionBOffset << "\n");
00267     RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
00268                       SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
00269                       HalfDiffKindBits);
00270 
00271     addRelocationForSection(R, SectionAID);
00272     addRelocationForSection(R, SectionBID);
00273 
00274     return ++RelI;
00275   }
00276 
00277 };
00278 }
00279 
00280 #undef DEBUG_TYPE
00281 
00282 #endif