xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
100b57cec5SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "../RuntimeDyldMachO.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #define DEBUG_TYPE "dyld"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric namespace llvm {
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric class RuntimeDyldMachOARM
190b57cec5SDimitry Andric     : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
200b57cec5SDimitry Andric private:
210b57cec5SDimitry Andric   typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric public:
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric   typedef uint32_t TargetPtrT;
260b57cec5SDimitry Andric 
RuntimeDyldMachOARM(RuntimeDyld::MemoryManager & MM,JITSymbolResolver & Resolver)270b57cec5SDimitry Andric   RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,
280b57cec5SDimitry Andric                       JITSymbolResolver &Resolver)
290b57cec5SDimitry Andric     : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
300b57cec5SDimitry Andric 
getMaxStubSize()310b57cec5SDimitry Andric   unsigned getMaxStubSize() const override { return 8; }
320b57cec5SDimitry Andric 
getStubAlignment()33*bdd1243dSDimitry Andric   Align getStubAlignment() override { return Align(4); }
340b57cec5SDimitry Andric 
getJITSymbolFlags(const SymbolRef & SR)350b57cec5SDimitry Andric   Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {
360b57cec5SDimitry Andric     auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);
370b57cec5SDimitry Andric     if (!Flags)
380b57cec5SDimitry Andric       return Flags.takeError();
390b57cec5SDimitry Andric     Flags->getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR);
400b57cec5SDimitry Andric     return Flags;
410b57cec5SDimitry Andric   }
420b57cec5SDimitry Andric 
modifyAddressBasedOnFlags(uint64_t Addr,JITSymbolFlags Flags)430b57cec5SDimitry Andric   uint64_t modifyAddressBasedOnFlags(uint64_t Addr,
440b57cec5SDimitry Andric                                      JITSymbolFlags Flags) const override {
450b57cec5SDimitry Andric     if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb)
460b57cec5SDimitry Andric       Addr |= 0x1;
470b57cec5SDimitry Andric     return Addr;
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric 
isAddrTargetThumb(unsigned SectionID,uint64_t Offset)500b57cec5SDimitry Andric   bool isAddrTargetThumb(unsigned SectionID, uint64_t Offset) {
510b57cec5SDimitry Andric     auto TargetObjAddr = Sections[SectionID].getObjAddress() + Offset;
520b57cec5SDimitry Andric     for (auto &KV : GlobalSymbolTable) {
530b57cec5SDimitry Andric       auto &Entry = KV.second;
540b57cec5SDimitry Andric       auto SymbolObjAddr =
550b57cec5SDimitry Andric           Sections[Entry.getSectionID()].getObjAddress() + Entry.getOffset();
560b57cec5SDimitry Andric       if (TargetObjAddr == SymbolObjAddr)
570b57cec5SDimitry Andric         return (Entry.getFlags().getTargetFlags() & ARMJITSymbolFlags::Thumb);
580b57cec5SDimitry Andric     }
590b57cec5SDimitry Andric     return false;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
decodeAddend(const RelocationEntry & RE)620b57cec5SDimitry Andric   Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
630b57cec5SDimitry Andric     const SectionEntry &Section = Sections[RE.SectionID];
640b57cec5SDimitry Andric     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     switch (RE.RelType) {
670b57cec5SDimitry Andric       default:
680b57cec5SDimitry Andric         return memcpyAddend(RE);
690b57cec5SDimitry Andric       case MachO::ARM_RELOC_BR24: {
700b57cec5SDimitry Andric         uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
710b57cec5SDimitry Andric         Temp &= 0x00ffffff; // Mask out the opcode.
720b57cec5SDimitry Andric         // Now we've got the shifted immediate, shift by 2, sign extend and ret.
730b57cec5SDimitry Andric         return SignExtend32<26>(Temp << 2);
740b57cec5SDimitry Andric       }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric       case MachO::ARM_THUMB_RELOC_BR22: {
770b57cec5SDimitry Andric         // This is a pair of instructions whose operands combine to provide 22
780b57cec5SDimitry Andric         // bits of displacement:
790b57cec5SDimitry Andric         // Encoding for high bits 1111 0XXX XXXX XXXX
800b57cec5SDimitry Andric         // Encoding for low bits  1111 1XXX XXXX XXXX
810b57cec5SDimitry Andric         uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
820b57cec5SDimitry Andric         if ((HighInsn & 0xf800) != 0xf000)
830b57cec5SDimitry Andric           return make_error<StringError>("Unrecognized thumb branch encoding "
840b57cec5SDimitry Andric                                          "(BR22 high bits)",
850b57cec5SDimitry Andric                                          inconvertibleErrorCode());
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric         uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
880b57cec5SDimitry Andric         if ((LowInsn & 0xf800) != 0xf800)
890b57cec5SDimitry Andric           return make_error<StringError>("Unrecognized thumb branch encoding "
900b57cec5SDimitry Andric                                          "(BR22 low bits)",
910b57cec5SDimitry Andric                                          inconvertibleErrorCode());
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric         return SignExtend64<23>(((HighInsn & 0x7ff) << 12) |
940b57cec5SDimitry Andric                                 ((LowInsn & 0x7ff) << 1));
950b57cec5SDimitry Andric       }
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   Expected<relocation_iterator>
processRelocationRef(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseObjT,ObjSectionToIDMap & ObjSectionToID,StubMap & Stubs)1000b57cec5SDimitry Andric   processRelocationRef(unsigned SectionID, relocation_iterator RelI,
1010b57cec5SDimitry Andric                        const ObjectFile &BaseObjT,
1020b57cec5SDimitry Andric                        ObjSectionToIDMap &ObjSectionToID,
1030b57cec5SDimitry Andric                        StubMap &Stubs) override {
1040b57cec5SDimitry Andric     const MachOObjectFile &Obj =
1050b57cec5SDimitry Andric         static_cast<const MachOObjectFile &>(BaseObjT);
1060b57cec5SDimitry Andric     MachO::any_relocation_info RelInfo =
1070b57cec5SDimitry Andric         Obj.getRelocation(RelI->getRawDataRefImpl());
1080b57cec5SDimitry Andric     uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric     // Set to true for thumb functions in this (or previous) TUs.
1110b57cec5SDimitry Andric     // Will be used to set the TargetIsThumbFunc member on the relocation entry.
1120b57cec5SDimitry Andric     bool TargetIsLocalThumbFunc = false;
1130b57cec5SDimitry Andric     if (Obj.getPlainRelocationExternal(RelInfo)) {
1140b57cec5SDimitry Andric       auto Symbol = RelI->getSymbol();
1150b57cec5SDimitry Andric       StringRef TargetName;
1160b57cec5SDimitry Andric       if (auto TargetNameOrErr = Symbol->getName())
1170b57cec5SDimitry Andric         TargetName = *TargetNameOrErr;
1180b57cec5SDimitry Andric       else
1190b57cec5SDimitry Andric         return TargetNameOrErr.takeError();
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric       // If the target is external but the value doesn't have a name then we've
1220b57cec5SDimitry Andric       // converted the value to a section/offset pair, but we still need to set
1230b57cec5SDimitry Andric       // the IsTargetThumbFunc bit, so look the value up in the globla symbol table.
1240b57cec5SDimitry Andric       auto EntryItr = GlobalSymbolTable.find(TargetName);
1250b57cec5SDimitry Andric       if (EntryItr != GlobalSymbolTable.end()) {
1260b57cec5SDimitry Andric         TargetIsLocalThumbFunc =
1270b57cec5SDimitry Andric           EntryItr->second.getFlags().getTargetFlags() &
1280b57cec5SDimitry Andric           ARMJITSymbolFlags::Thumb;
1290b57cec5SDimitry Andric       }
1300b57cec5SDimitry Andric     }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     if (Obj.isRelocationScattered(RelInfo)) {
1330b57cec5SDimitry Andric       if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
1340b57cec5SDimitry Andric         return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
1350b57cec5SDimitry Andric                                              ObjSectionToID);
1360b57cec5SDimitry Andric       else if (RelType == MachO::GENERIC_RELOC_VANILLA)
1370b57cec5SDimitry Andric         return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,
1380b57cec5SDimitry Andric                                        TargetIsLocalThumbFunc);
1390b57cec5SDimitry Andric       else
1400b57cec5SDimitry Andric         return ++RelI;
1410b57cec5SDimitry Andric     }
1420b57cec5SDimitry Andric 
143349cc55cSDimitry Andric     // Validate the relocation type.
1440b57cec5SDimitry Andric     switch (RelType) {
1450b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);
1460b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
1470b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
1480b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
1490b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);
1500b57cec5SDimitry Andric     UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
1510b57cec5SDimitry Andric     default:
1520b57cec5SDimitry Andric       if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)
1530b57cec5SDimitry Andric         return make_error<RuntimeDyldError>(("MachO ARM relocation type " +
1540b57cec5SDimitry Andric                                              Twine(RelType) +
1550b57cec5SDimitry Andric                                              " is out of range").str());
1560b57cec5SDimitry Andric       break;
1570b57cec5SDimitry Andric     }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric     RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
1600b57cec5SDimitry Andric     if (auto AddendOrErr = decodeAddend(RE))
1610b57cec5SDimitry Andric       RE.Addend = *AddendOrErr;
1620b57cec5SDimitry Andric     else
1630b57cec5SDimitry Andric       return AddendOrErr.takeError();
1640b57cec5SDimitry Andric     RE.IsTargetThumbFunc = TargetIsLocalThumbFunc;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric     RelocationValueRef Value;
1670b57cec5SDimitry Andric     if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
1680b57cec5SDimitry Andric       Value = *ValueOrErr;
1690b57cec5SDimitry Andric     else
1700b57cec5SDimitry Andric       return ValueOrErr.takeError();
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric     // If this is a branch from a thumb function (BR22) then make sure we mark
1730b57cec5SDimitry Andric     // the value as being a thumb stub: we don't want to mix it up with an ARM
1740b57cec5SDimitry Andric     // stub targeting the same function.
1750b57cec5SDimitry Andric     if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
1760b57cec5SDimitry Andric       Value.IsStubThumb = true;
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric     if (RE.IsPCRel)
1790b57cec5SDimitry Andric       makeValueAddendPCRel(Value, RelI,
1800b57cec5SDimitry Andric                            (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric     // If this is a non-external branch target check whether Value points to a
1830b57cec5SDimitry Andric     // thumb func.
1840b57cec5SDimitry Andric     if (!Value.SymbolName && (RelType == MachO::ARM_RELOC_BR24 ||
1850b57cec5SDimitry Andric                               RelType == MachO::ARM_THUMB_RELOC_BR22))
1860b57cec5SDimitry Andric       RE.IsTargetThumbFunc = isAddrTargetThumb(Value.SectionID, Value.Offset);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     if (RE.RelType == MachO::ARM_RELOC_BR24 ||
1890b57cec5SDimitry Andric         RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
1900b57cec5SDimitry Andric       processBranchRelocation(RE, Value, Stubs);
1910b57cec5SDimitry Andric     else {
1920b57cec5SDimitry Andric       RE.Addend = Value.Offset;
1930b57cec5SDimitry Andric       if (Value.SymbolName)
1940b57cec5SDimitry Andric         addRelocationForSymbol(RE, Value.SymbolName);
1950b57cec5SDimitry Andric       else
1960b57cec5SDimitry Andric         addRelocationForSection(RE, Value.SectionID);
1970b57cec5SDimitry Andric     }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric     return ++RelI;
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric 
resolveRelocation(const RelocationEntry & RE,uint64_t Value)2020b57cec5SDimitry Andric   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
2030b57cec5SDimitry Andric     LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
2040b57cec5SDimitry Andric     const SectionEntry &Section = Sections[RE.SectionID];
2050b57cec5SDimitry Andric     uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     // If the relocation is PC-relative, the value to be encoded is the
2080b57cec5SDimitry Andric     // pointer difference.
2090b57cec5SDimitry Andric     if (RE.IsPCRel) {
2100b57cec5SDimitry Andric       uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
2110b57cec5SDimitry Andric       Value -= FinalAddress;
2120b57cec5SDimitry Andric       // ARM PCRel relocations have an effective-PC offset of two instructions
2130b57cec5SDimitry Andric       // (four bytes in Thumb mode, 8 bytes in ARM mode).
2140b57cec5SDimitry Andric       Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;
2150b57cec5SDimitry Andric     }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     switch (RE.RelType) {
2180b57cec5SDimitry Andric     case MachO::ARM_THUMB_RELOC_BR22: {
2190b57cec5SDimitry Andric       Value += RE.Addend;
2200b57cec5SDimitry Andric       uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
2210b57cec5SDimitry Andric       assert((HighInsn & 0xf800) == 0xf000 &&
2220b57cec5SDimitry Andric              "Unrecognized thumb branch encoding (BR22 high bits)");
2230b57cec5SDimitry Andric       HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff);
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric       uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
2260b57cec5SDimitry Andric       assert((LowInsn & 0xf800) == 0xf800 &&
2270b57cec5SDimitry Andric              "Unrecognized thumb branch encoding (BR22 low bits)");
2280b57cec5SDimitry Andric       LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff);
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric       writeBytesUnaligned(HighInsn, LocalAddress, 2);
2310b57cec5SDimitry Andric       writeBytesUnaligned(LowInsn, LocalAddress + 2, 2);
2320b57cec5SDimitry Andric       break;
2330b57cec5SDimitry Andric     }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric     case MachO::ARM_RELOC_VANILLA:
2360b57cec5SDimitry Andric       if (RE.IsTargetThumbFunc)
2370b57cec5SDimitry Andric         Value |= 0x01;
2380b57cec5SDimitry Andric       writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
2390b57cec5SDimitry Andric       break;
2400b57cec5SDimitry Andric     case MachO::ARM_RELOC_BR24: {
2410b57cec5SDimitry Andric       // Mask the value into the target address. We know instructions are
2420b57cec5SDimitry Andric       // 32-bit aligned, so we can do it all at once.
2430b57cec5SDimitry Andric       Value += RE.Addend;
2440b57cec5SDimitry Andric       // The low two bits of the value are not encoded.
2450b57cec5SDimitry Andric       Value >>= 2;
2460b57cec5SDimitry Andric       // Mask the value to 24 bits.
2470b57cec5SDimitry Andric       uint64_t FinalValue = Value & 0xffffff;
2480b57cec5SDimitry Andric       // FIXME: If the destination is a Thumb function (and the instruction
2490b57cec5SDimitry Andric       // is a non-predicated BL instruction), we need to change it to a BLX
2500b57cec5SDimitry Andric       // instruction instead.
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric       // Insert the value into the instruction.
2530b57cec5SDimitry Andric       uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
2540b57cec5SDimitry Andric       writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric       break;
2570b57cec5SDimitry Andric     }
2580b57cec5SDimitry Andric     case MachO::ARM_RELOC_HALF_SECTDIFF: {
2590b57cec5SDimitry Andric       uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
2600b57cec5SDimitry Andric       uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
2610b57cec5SDimitry Andric       assert((Value == SectionABase || Value == SectionBBase) &&
2620b57cec5SDimitry Andric              "Unexpected HALFSECTDIFF relocation value.");
2630b57cec5SDimitry Andric       Value = SectionABase - SectionBBase + RE.Addend;
2640b57cec5SDimitry Andric       if (RE.Size & 0x1) // :upper16:
2650b57cec5SDimitry Andric         Value = (Value >> 16);
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric       bool IsThumb = RE.Size & 0x2;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric       Value &= 0xffff;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric       uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric       if (IsThumb)
2740b57cec5SDimitry Andric         Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) |
2750b57cec5SDimitry Andric                ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) |
2760b57cec5SDimitry Andric                ((Value & 0x00ff) << 16);
2770b57cec5SDimitry Andric       else
2780b57cec5SDimitry Andric         Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
2790b57cec5SDimitry Andric       writeBytesUnaligned(Insn, LocalAddress, 4);
2800b57cec5SDimitry Andric       break;
2810b57cec5SDimitry Andric     }
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric     default:
2840b57cec5SDimitry Andric       llvm_unreachable("Invalid relocation type");
2850b57cec5SDimitry Andric     }
2860b57cec5SDimitry Andric   }
2870b57cec5SDimitry Andric 
finalizeSection(const ObjectFile & Obj,unsigned SectionID,const SectionRef & Section)2880b57cec5SDimitry Andric   Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
2890b57cec5SDimitry Andric                        const SectionRef &Section) {
2900b57cec5SDimitry Andric     StringRef Name;
2918bcb0991SDimitry Andric     if (Expected<StringRef> NameOrErr = Section.getName())
2928bcb0991SDimitry Andric       Name = *NameOrErr;
2938bcb0991SDimitry Andric     else
2948bcb0991SDimitry Andric       consumeError(NameOrErr.takeError());
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric     if (Name == "__nl_symbol_ptr")
2970b57cec5SDimitry Andric       return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
2980b57cec5SDimitry Andric                                                    Section, SectionID);
2990b57cec5SDimitry Andric     return Error::success();
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric private:
3030b57cec5SDimitry Andric 
processBranchRelocation(const RelocationEntry & RE,const RelocationValueRef & Value,StubMap & Stubs)3040b57cec5SDimitry Andric   void processBranchRelocation(const RelocationEntry &RE,
3050b57cec5SDimitry Andric                                const RelocationValueRef &Value,
3060b57cec5SDimitry Andric                                StubMap &Stubs) {
3070b57cec5SDimitry Andric     // This is an ARM branch relocation, need to use a stub function.
3080b57cec5SDimitry Andric     // Look up for existing stub.
3090b57cec5SDimitry Andric     SectionEntry &Section = Sections[RE.SectionID];
3100b57cec5SDimitry Andric     RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
3110b57cec5SDimitry Andric     uint8_t *Addr;
3120b57cec5SDimitry Andric     if (i != Stubs.end()) {
3130b57cec5SDimitry Andric       Addr = Section.getAddressWithOffset(i->second);
3140b57cec5SDimitry Andric     } else {
3150b57cec5SDimitry Andric       // Create a new stub function.
3160b57cec5SDimitry Andric       assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");
3170b57cec5SDimitry Andric       Stubs[Value] = Section.getStubOffset();
3180b57cec5SDimitry Andric       uint32_t StubOpcode = 0;
3190b57cec5SDimitry Andric       if (RE.RelType == MachO::ARM_RELOC_BR24)
3200b57cec5SDimitry Andric         StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4]
3210b57cec5SDimitry Andric       else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
3220b57cec5SDimitry Andric         StubOpcode = 0xf000f8df; // ldr pc, [pc]
3230b57cec5SDimitry Andric       else
3240b57cec5SDimitry Andric         llvm_unreachable("Unrecognized relocation");
3250b57cec5SDimitry Andric       Addr = Section.getAddressWithOffset(Section.getStubOffset());
3260b57cec5SDimitry Andric       writeBytesUnaligned(StubOpcode, Addr, 4);
3270b57cec5SDimitry Andric       uint8_t *StubTargetAddr = Addr + 4;
3280b57cec5SDimitry Andric       RelocationEntry StubRE(
3290b57cec5SDimitry Andric           RE.SectionID, StubTargetAddr - Section.getAddress(),
3300b57cec5SDimitry Andric           MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
3310b57cec5SDimitry Andric       StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;
3320b57cec5SDimitry Andric       if (Value.SymbolName)
3330b57cec5SDimitry Andric         addRelocationForSymbol(StubRE, Value.SymbolName);
3340b57cec5SDimitry Andric       else
3350b57cec5SDimitry Andric         addRelocationForSection(StubRE, Value.SectionID);
3360b57cec5SDimitry Andric       Section.advanceStubOffset(getMaxStubSize());
3370b57cec5SDimitry Andric     }
3380b57cec5SDimitry Andric     RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
3390b57cec5SDimitry Andric                              RE.IsPCRel, RE.Size);
3400b57cec5SDimitry Andric     resolveRelocation(TargetRE, (uint64_t)Addr);
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   Expected<relocation_iterator>
processHALFSECTDIFFRelocation(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseTObj,ObjSectionToIDMap & ObjSectionToID)3440b57cec5SDimitry Andric   processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
3450b57cec5SDimitry Andric                                 const ObjectFile &BaseTObj,
3460b57cec5SDimitry Andric                                 ObjSectionToIDMap &ObjSectionToID) {
3470b57cec5SDimitry Andric     const MachOObjectFile &MachO =
3480b57cec5SDimitry Andric         static_cast<const MachOObjectFile&>(BaseTObj);
3490b57cec5SDimitry Andric     MachO::any_relocation_info RE =
3500b57cec5SDimitry Andric         MachO.getRelocation(RelI->getRawDataRefImpl());
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric     // For a half-diff relocation the length bits actually record whether this
3530b57cec5SDimitry Andric     // is a movw/movt, and whether this is arm or thumb.
3540b57cec5SDimitry Andric     // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
3550b57cec5SDimitry Andric     // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
3560b57cec5SDimitry Andric     unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
3570b57cec5SDimitry Andric     bool IsThumb = HalfDiffKindBits & 0x2;
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric     SectionEntry &Section = Sections[SectionID];
3600b57cec5SDimitry Andric     uint32_t RelocType = MachO.getAnyRelocationType(RE);
3610b57cec5SDimitry Andric     bool IsPCRel = MachO.getAnyRelocationPCRel(RE);
3620b57cec5SDimitry Andric     uint64_t Offset = RelI->getOffset();
3630b57cec5SDimitry Andric     uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
3640b57cec5SDimitry Andric     int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric     if (IsThumb)
3670b57cec5SDimitry Andric       Immediate = ((Immediate & 0x0000000f) << 12) |
3680b57cec5SDimitry Andric                   ((Immediate & 0x00000400) << 1) |
3690b57cec5SDimitry Andric                   ((Immediate & 0x70000000) >> 20) |
3700b57cec5SDimitry Andric                   ((Immediate & 0x00ff0000) >> 16);
3710b57cec5SDimitry Andric     else
3720b57cec5SDimitry Andric       Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric     ++RelI;
3750b57cec5SDimitry Andric     MachO::any_relocation_info RE2 =
3760b57cec5SDimitry Andric       MachO.getRelocation(RelI->getRawDataRefImpl());
3770b57cec5SDimitry Andric     uint32_t AddrA = MachO.getScatteredRelocationValue(RE);
3780b57cec5SDimitry Andric     section_iterator SAI = getSectionByAddress(MachO, AddrA);
3790b57cec5SDimitry Andric     assert(SAI != MachO.section_end() && "Can't find section for address A");
3800b57cec5SDimitry Andric     uint64_t SectionABase = SAI->getAddress();
3810b57cec5SDimitry Andric     uint64_t SectionAOffset = AddrA - SectionABase;
3820b57cec5SDimitry Andric     SectionRef SectionA = *SAI;
3830b57cec5SDimitry Andric     bool IsCode = SectionA.isText();
3840b57cec5SDimitry Andric     uint32_t SectionAID = ~0U;
3850b57cec5SDimitry Andric     if (auto SectionAIDOrErr =
3860b57cec5SDimitry Andric           findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))
3870b57cec5SDimitry Andric       SectionAID = *SectionAIDOrErr;
3880b57cec5SDimitry Andric     else
3890b57cec5SDimitry Andric       return SectionAIDOrErr.takeError();
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric     uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);
3920b57cec5SDimitry Andric     section_iterator SBI = getSectionByAddress(MachO, AddrB);
3930b57cec5SDimitry Andric     assert(SBI != MachO.section_end() && "Can't find section for address B");
3940b57cec5SDimitry Andric     uint64_t SectionBBase = SBI->getAddress();
3950b57cec5SDimitry Andric     uint64_t SectionBOffset = AddrB - SectionBBase;
3960b57cec5SDimitry Andric     SectionRef SectionB = *SBI;
3970b57cec5SDimitry Andric     uint32_t SectionBID = ~0U;
3980b57cec5SDimitry Andric     if (auto SectionBIDOrErr =
3990b57cec5SDimitry Andric           findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))
4000b57cec5SDimitry Andric       SectionBID = *SectionBIDOrErr;
4010b57cec5SDimitry Andric     else
4020b57cec5SDimitry Andric       return SectionBIDOrErr.takeError();
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;
4050b57cec5SDimitry Andric     unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
4060b57cec5SDimitry Andric     uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
4070b57cec5SDimitry Andric     int64_t Addend = FullImmVal - (AddrA - AddrB);
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric     // addend = Encoded - Expected
4100b57cec5SDimitry Andric     //        = Encoded - (AddrA - AddrB)
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA
4130b57cec5SDimitry Andric                       << ", AddrB: " << AddrB << ", Addend: " << Addend
4140b57cec5SDimitry Andric                       << ", SectionA ID: " << SectionAID << ", SectionAOffset: "
4150b57cec5SDimitry Andric                       << SectionAOffset << ", SectionB ID: " << SectionBID
4160b57cec5SDimitry Andric                       << ", SectionBOffset: " << SectionBOffset << "\n");
4170b57cec5SDimitry Andric     RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
4180b57cec5SDimitry Andric                       SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
4190b57cec5SDimitry Andric                       HalfDiffKindBits);
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric     addRelocationForSection(R, SectionAID);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric     return ++RelI;
4240b57cec5SDimitry Andric   }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric };
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric #undef DEBUG_TYPE
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric #endif
432