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