diff options
author | Lang Hames <lhames@gmail.com> | 2017-08-09 20:19:27 +0000 |
---|---|---|
committer | Lang Hames <lhames@gmail.com> | 2017-08-09 20:19:27 +0000 |
commit | 14a22a442d8aa6bee8c828872b82b7dd722dc7b8 (patch) | |
tree | df3669f3e144a69fb5766c7eac17dfe07e8a2c0f /llvm/lib | |
parent | 7d928cc596bdfe3c0f8b60e9a5c605d1b0f4cec2 (diff) | |
download | bcm5719-llvm-14a22a442d8aa6bee8c828872b82b7dd722dc7b8.tar.gz bcm5719-llvm-14a22a442d8aa6bee8c828872b82b7dd722dc7b8.zip |
[RuntimeDyld][ORC] Add support for Thumb mode to RuntimeDyldMachOARM.
This patch adds support for thumb relocations to RuntimeDyldMachOARM, and adds
a target-specific flags field to JITSymbolFlags (so that on ARM we can record
whether each symbol is Thumb-mode code).
RuntimeDyldImpl::emitSection is modified to ensure that stubs memory is
correctly aligned based on the size returned by getStubAlignment().
llvm-svn: 310517
Diffstat (limited to 'llvm/lib')
6 files changed, 200 insertions, 35 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp index 8769dcf7374..87059ef2b88 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp @@ -39,3 +39,11 @@ llvm::JITSymbolFlags::fromObjectSymbol(const object::BasicSymbolRef &Symbol) { Flags |= JITSymbolFlags::Exported; return Flags; } + +ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol( + const object::BasicSymbolRef &Symbol) { + ARMJITSymbolFlags Flags; + if (Symbol.getFlags() & object::BasicSymbolRef::SF_Thumb) + Flags |= ARMJITSymbolFlags::Thumb; + return Flags; +} diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 8198836f7a0..4d1d74cf34a 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -233,7 +233,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { return NameOrErr.takeError(); // Compute JIT symbol flags. - JITSymbolFlags JITSymFlags = JITSymbolFlags::fromObjectSymbol(*I); + JITSymbolFlags JITSymFlags = getJITSymbolFlags(*I); // If this is a weak definition, check to see if there's a strong one. // If there is, skip this symbol (we won't be providing it: the strong @@ -616,6 +616,10 @@ void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst, } } +JITSymbolFlags RuntimeDyldImpl::getJITSymbolFlags(const BasicSymbolRef &SR) { + return JITSymbolFlags::fromObjectSymbol(SR); +} + Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, CommonSymbolList &CommonSymbols) { if (CommonSymbols.empty()) @@ -685,7 +689,7 @@ Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, Addr += AlignOffset; Offset += AlignOffset; } - JITSymbolFlags JITSymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + JITSymbolFlags JITSymFlags = getJITSymbolFlags(Sym); DEBUG(dbgs() << "Allocating common symbol " << Name << " address " << format("%p", Addr) << "\n"); GlobalSymbolTable[Name] = @@ -746,8 +750,11 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj, // Code section alignment needs to be at least as high as stub alignment or // padding calculations may by incorrect when the section is remapped to a // higher alignment. - if (IsCode) + if (IsCode) { Alignment = std::max(Alignment, getStubAlignment()); + if (StubBufSize > 0) + PaddingSize += getStubAlignment() - 1; + } // Some sections, such as debug info, don't need to be loaded for execution. // Process those only if explicitly requested. @@ -771,8 +778,13 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj, // Fill in any extra bytes we allocated for padding if (PaddingSize != 0) { memset(Addr + DataSize, 0, PaddingSize); - // Update the DataSize variable so that the stub offset is set correctly. + // Update the DataSize variable to include padding. DataSize += PaddingSize; + + // Align DataSize to stub alignment if we have any stubs (PaddingSize will + // have been increased above to account for this). + if (StubBufSize > 0) + DataSize &= ~(getStubAlignment() - 1); } DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name @@ -864,7 +876,7 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, } else if (Arch == Triple::arm || Arch == Triple::armeb) { // TODO: There is only ARM far stub now. We should add the Thumb stub, // and stubs for branches Thumb - ARM and ARM - Thumb. - writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc,<label> + writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4] return Addr + 4; } else if (IsMipsO32ABI) { // 0: 3c190000 lui t9,%hi(addr). @@ -971,15 +983,17 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { resolveRelocationList(Relocs, 0); } else { uint64_t Addr = 0; + JITSymbolFlags Flags; RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name); if (Loc == GlobalSymbolTable.end()) { // This is an external symbol, try to get its address from the symbol // resolver. // First search for the symbol in this logical dylib. if (auto Sym = Resolver.findSymbolInLogicalDylib(Name.data())) { - if (auto AddrOrErr = Sym.getAddress()) + if (auto AddrOrErr = Sym.getAddress()) { Addr = *AddrOrErr; - else + Flags = Sym.getFlags(); + } else return AddrOrErr.takeError(); } else if (auto Err = Sym.takeError()) return Err; @@ -987,9 +1001,10 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { // If that fails, try searching for an external symbol. if (!Addr) { if (auto Sym = Resolver.findSymbol(Name.data())) { - if (auto AddrOrErr = Sym.getAddress()) + if (auto AddrOrErr = Sym.getAddress()) { Addr = *AddrOrErr; - else + Flags = Sym.getFlags(); + } else return AddrOrErr.takeError(); } else if (auto Err = Sym.takeError()) return Err; @@ -1007,6 +1022,7 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { const auto &SymInfo = Loc->second; Addr = getSectionLoadAddress(SymInfo.getSectionID()) + SymInfo.getOffset(); + Flags = SymInfo.getFlags(); } // FIXME: Implement error handling that doesn't kill the host program! @@ -1017,6 +1033,12 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { // If Resolver returned UINT64_MAX, the client wants to handle this symbol // manually and we shouldn't resolve its relocations. if (Addr != UINT64_MAX) { + + // Tweak the address based on the symbol flags if necessary. + // For example, this is used by RuntimeDyldMachOARM to toggle the low bit + // if the target symbol is Thumb. + Addr = modifyAddressBasedOnFlags(Addr, Flags); + DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" << format("0x%lx", Addr) << "\n"); // This list may have been updated when we called getSymbolAddress, so diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index 95b04fd9325..e046a8504e9 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -149,8 +149,8 @@ public: /// The size of this relocation (MachO specific). unsigned Size; - // COFF specific. - bool IsTargetThumbFunc; + // ARM (MachO and COFF) specific. + bool IsTargetThumbFunc = false; RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) : SectionID(id), Offset(offset), RelType(type), Addend(addend), @@ -195,12 +195,14 @@ public: uint64_t Offset; int64_t Addend; const char *SymbolName; + bool IsStubThumb = false; RelocationValueRef() : SectionID(0), Offset(0), Addend(0), SymbolName(nullptr) {} inline bool operator==(const RelocationValueRef &Other) const { return SectionID == Other.SectionID && Offset == Other.Offset && - Addend == Other.Addend && SymbolName == Other.SymbolName; + Addend == Other.Addend && SymbolName == Other.SymbolName && + IsStubThumb == Other.IsStubThumb; } inline bool operator<(const RelocationValueRef &Other) const { if (SectionID != Other.SectionID) @@ -209,6 +211,8 @@ public: return Offset < Other.Offset; if (Addend != Other.Addend) return Addend < Other.Addend; + if (IsStubThumb != Other.IsStubThumb) + return IsStubThumb < Other.IsStubThumb; return SymbolName < Other.SymbolName; } }; @@ -216,21 +220,21 @@ public: /// @brief Symbol info for RuntimeDyld. class SymbolTableEntry { public: - SymbolTableEntry() - : Offset(0), SectionID(0) {} + SymbolTableEntry() = default; SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags) : Offset(Offset), SectionID(SectionID), Flags(Flags) {} unsigned getSectionID() const { return SectionID; } uint64_t getOffset() const { return Offset; } + void setOffset(uint64_t NewOffset) { Offset = NewOffset; } JITSymbolFlags getFlags() const { return Flags; } private: - uint64_t Offset; - unsigned SectionID; - JITSymbolFlags Flags; + uint64_t Offset = 0; + unsigned SectionID = 0; + JITSymbolFlags Flags = JITSymbolFlags::None; }; typedef StringMap<SymbolTableEntry> RTDyldSymbolTable; @@ -365,6 +369,18 @@ protected: /// Dst. void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const; + /// Generate JITSymbolFlags from a libObject symbol. + virtual JITSymbolFlags getJITSymbolFlags(const BasicSymbolRef &Sym); + + /// Modify the given target address based on the given symbol flags. + /// This can be used by subclasses to tweak addresses based on symbol flags, + /// For example: the MachO/ARM target uses it to set the low bit if the target + /// is a thumb symbol. + virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr, + JITSymbolFlags Flags) const { + return Addr; + } + /// \brief Given the common symbols discovered in the object file, emit a /// new section for them and update the symbol mappings in the object and /// symbol table. @@ -493,6 +509,12 @@ public: if (SymEntry.getSectionID() != AbsoluteSymbolSection) SectionAddr = getSectionLoadAddress(SymEntry.getSectionID()); uint64_t TargetAddr = SectionAddr + SymEntry.getOffset(); + + // FIXME: Have getSymbol should return the actual address and the client + // modify it based on the flags. This will require clients to be + // aware of the target architecture, which we should build + // infrastructure for. + TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags()); return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags()); } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 80e9c7ac18a..b0561f68edb 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -55,7 +55,8 @@ Expected<relocation_iterator> RuntimeDyldMachO::processScatteredVANILLA( unsigned SectionID, relocation_iterator RelI, const ObjectFile &BaseObjT, - RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) { + RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, + bool TargetIsLocalThumbFunc) { const MachOObjectFile &Obj = static_cast<const MachOObjectFile&>(BaseObjT); MachO::any_relocation_info RE = @@ -85,6 +86,7 @@ RuntimeDyldMachO::processScatteredVANILLA( Addend -= SectionBaseAddr; RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size); + R.IsTargetThumbFunc = TargetIsLocalThumbFunc; addRelocationForSection(R, TargetSectionID); diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 67a5020fc4f..d71ca4e5495 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -83,7 +83,8 @@ protected: Expected<relocation_iterator> processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI, const ObjectFile &BaseObjT, - RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID); + RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, + bool TargetIsLocalThumbFunc = false); /// Construct a RelocationValueRef representing the relocation target. /// For Symbols in known sections, this will return a RelocationValueRef diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h index 43461de4c49..990629de2f1 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h @@ -34,7 +34,20 @@ public: unsigned getStubAlignment() override { return 4; } - int64_t decodeAddend(const RelocationEntry &RE) const { + JITSymbolFlags getJITSymbolFlags(const BasicSymbolRef &SR) override { + auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR); + Flags.getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR); + return Flags; + } + + uint64_t modifyAddressBasedOnFlags(uint64_t Addr, + JITSymbolFlags Flags) const override { + if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb) + Addr |= 0x1; + return Addr; + } + + Expected<int64_t> decodeAddend(const RelocationEntry &RE) const { const SectionEntry &Section = Sections[RE.SectionID]; uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); @@ -47,6 +60,27 @@ public: // Now we've got the shifted immediate, shift by 2, sign extend and ret. return SignExtend32<26>(Temp << 2); } + + case MachO::ARM_THUMB_RELOC_BR22: { + // This is a pair of instructions whose operands combine to provide 22 + // bits of displacement: + // Encoding for high bits 1111 0XXX XXXX XXXX + // Encoding for low bits 1111 1XXX XXXX XXXX + uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); + if ((HighInsn & 0xf800) != 0xf000) + return make_error<StringError>("Unrecognized thumb branch encoding " + "(BR22 high bits)", + inconvertibleErrorCode()); + + uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); + if ((LowInsn & 0xf800) != 0xf800) + return make_error<StringError>("Unrecognized thumb branch encoding " + "(BR22 low bits)", + inconvertibleErrorCode()); + + return SignExtend64<23>(((HighInsn & 0x7ff) << 12) | + ((LowInsn & 0x7ff) << 1)); + } } } @@ -61,12 +95,35 @@ public: Obj.getRelocation(RelI->getRawDataRefImpl()); uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + // Set to true for thumb functions in this (or previous) TUs. + // Will be used to set the TargetIsThumbFunc member on the relocation entry. + bool TargetIsLocalThumbFunc = false; + if (Obj.getPlainRelocationExternal(RelInfo)) { + auto Symbol = RelI->getSymbol(); + StringRef TargetName; + if (auto TargetNameOrErr = Symbol->getName()) + TargetName = *TargetNameOrErr; + else + return TargetNameOrErr.takeError(); + + // If the target is external but the value doesn't have a name then we've + // converted the value to a section/offset pair, but we still need to set + // the IsTargetThumbFunc bit, so look the value up in the globla symbol table. + auto EntryItr = GlobalSymbolTable.find(TargetName); + if (EntryItr != GlobalSymbolTable.end()) { + TargetIsLocalThumbFunc = + EntryItr->second.getFlags().getTargetFlags() & + ARMJITSymbolFlags::Thumb; + } + } + if (Obj.isRelocationScattered(RelInfo)) { if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF) return processHALFSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID); else if (RelType == MachO::GENERIC_RELOC_VANILLA) - return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); + return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID, + TargetIsLocalThumbFunc); else return ++RelI; } @@ -77,7 +134,6 @@ public: UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF); UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF); UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR); - UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_RELOC_BR22); UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH); UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF); default: @@ -89,17 +145,30 @@ public: } RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); - RE.Addend = decodeAddend(RE); + if (auto AddendOrErr = decodeAddend(RE)) + RE.Addend = *AddendOrErr; + else + return AddendOrErr.takeError(); + RE.IsTargetThumbFunc = TargetIsLocalThumbFunc; + RelocationValueRef Value; if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) Value = *ValueOrErr; else return ValueOrErr.takeError(); + // If this is a branch from a thumb function (BR22) then make sure we mark + // the value as being a thumb stub: we don't want to mix it up with an ARM + // stub targeting the same function. + if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) + Value.IsStubThumb = TargetIsLocalThumbFunc; + if (RE.IsPCRel) - makeValueAddendPCRel(Value, RelI, 8); + makeValueAddendPCRel(Value, RelI, + (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8); - if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24) + if (RE.RelType == MachO::ARM_RELOC_BR24 || + RE.RelType == MachO::ARM_THUMB_RELOC_BR22) processBranchRelocation(RE, Value, Stubs); else { RE.Addend = Value.Offset; @@ -124,12 +193,30 @@ public: Value -= FinalAddress; // ARM PCRel relocations have an effective-PC offset of two instructions // (four bytes in Thumb mode, 8 bytes in ARM mode). - // FIXME: For now, assume ARM mode. - Value -= 8; + Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8; } switch (RE.RelType) { + case MachO::ARM_THUMB_RELOC_BR22: { + Value += RE.Addend; + uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); + assert((HighInsn & 0xf800) == 0xf000 && + "Unrecognized thumb branch encoding (BR22 high bits)"); + HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff); + + uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); + assert((LowInsn & 0xf800) != 0xf8000 && + "Unrecognized thumb branch encoding (BR22 low bits)"); + LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff); + + writeBytesUnaligned(HighInsn, LocalAddress, 2); + writeBytesUnaligned(LowInsn, LocalAddress + 2, 2); + break; + } + case MachO::ARM_RELOC_VANILLA: + if (RE.IsTargetThumbFunc) + Value |= 0x01; writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); break; case MachO::ARM_RELOC_BR24: { @@ -158,10 +245,19 @@ public: Value = SectionABase - SectionBBase + RE.Addend; if (RE.Size & 0x1) // :upper16: Value = (Value >> 16); + + bool IsThumb = RE.Size & 0x2; + Value &= 0xffff; uint32_t Insn = readBytesUnaligned(LocalAddress, 4); - Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); + + if (IsThumb) + Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) | + ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) | + ((Value & 0x00ff) << 16); + else + Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); writeBytesUnaligned(Insn, LocalAddress, 4); break; } @@ -196,17 +292,26 @@ private: Addr = Section.getAddressWithOffset(i->second); } else { // Create a new stub function. + assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub"); Stubs[Value] = Section.getStubOffset(); - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset())); + uint32_t StubOpcode = 0; + if (RE.RelType == MachO::ARM_RELOC_BR24) + StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4] + else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) + StubOpcode = 0xf000f8df; // ldr pc, [pc] + else + llvm_unreachable("Unrecognized relocation"); + Addr = Section.getAddressWithOffset(Section.getStubOffset()); + writeBytesUnaligned(StubOpcode, Addr, 4); + uint8_t *StubTargetAddr = Addr + 4; RelocationEntry StubRE( RE.SectionID, StubTargetAddr - Section.getAddress(), MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2); + StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc; if (Value.SymbolName) addRelocationForSymbol(StubRE, Value.SymbolName); else addRelocationForSection(StubRE, Value.SectionID); - Addr = Section.getAddressWithOffset(Section.getStubOffset()); Section.advanceStubOffset(getMaxStubSize()); } RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0, @@ -223,14 +328,12 @@ private: MachO::any_relocation_info RE = MachO.getRelocation(RelI->getRawDataRefImpl()); - // For a half-diff relocation the length bits actually record whether this // is a movw/movt, and whether this is arm or thumb. // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1). // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1). unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE); - if (HalfDiffKindBits & 0x2) - llvm_unreachable("Thumb not yet supported."); + bool IsThumb = HalfDiffKindBits & 0x2; SectionEntry &Section = Sections[SectionID]; uint32_t RelocType = MachO.getAnyRelocationType(RE); @@ -238,7 +341,14 @@ private: uint64_t Offset = RelI->getOffset(); uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out. - Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); + + if (IsThumb) + Immediate = ((Immediate & 0x0000000f) << 12) | + ((Immediate & 0x00000400) << 1) | + ((Immediate & 0x70000000) >> 20) | + ((Immediate & 0x00ff0000) >> 16); + else + Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); ++RelI; MachO::any_relocation_info RE2 = |