Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
35294 views
//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H9#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H1011#include "../RuntimeDyldMachO.h"1213#define DEBUG_TYPE "dyld"1415namespace llvm {1617class RuntimeDyldMachOARM18: public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {19private:20typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;2122public:2324typedef uint32_t TargetPtrT;2526RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,27JITSymbolResolver &Resolver)28: RuntimeDyldMachOCRTPBase(MM, Resolver) {}2930unsigned getMaxStubSize() const override { return 8; }3132Align getStubAlignment() override { return Align(4); }3334Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {35auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);36if (!Flags)37return Flags.takeError();38Flags->getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR);39return Flags;40}4142uint64_t modifyAddressBasedOnFlags(uint64_t Addr,43JITSymbolFlags Flags) const override {44if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb)45Addr |= 0x1;46return Addr;47}4849bool isAddrTargetThumb(unsigned SectionID, uint64_t Offset) {50auto TargetObjAddr = Sections[SectionID].getObjAddress() + Offset;51for (auto &KV : GlobalSymbolTable) {52auto &Entry = KV.second;53auto SymbolObjAddr =54Sections[Entry.getSectionID()].getObjAddress() + Entry.getOffset();55if (TargetObjAddr == SymbolObjAddr)56return (Entry.getFlags().getTargetFlags() & ARMJITSymbolFlags::Thumb);57}58return false;59}6061Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {62const SectionEntry &Section = Sections[RE.SectionID];63uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);6465switch (RE.RelType) {66default:67return memcpyAddend(RE);68case MachO::ARM_RELOC_BR24: {69uint32_t Temp = readBytesUnaligned(LocalAddress, 4);70Temp &= 0x00ffffff; // Mask out the opcode.71// Now we've got the shifted immediate, shift by 2, sign extend and ret.72return SignExtend32<26>(Temp << 2);73}7475case MachO::ARM_THUMB_RELOC_BR22: {76// This is a pair of instructions whose operands combine to provide 2277// bits of displacement:78// Encoding for high bits 1111 0XXX XXXX XXXX79// Encoding for low bits 1111 1XXX XXXX XXXX80uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);81if ((HighInsn & 0xf800) != 0xf000)82return make_error<StringError>("Unrecognized thumb branch encoding "83"(BR22 high bits)",84inconvertibleErrorCode());8586uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);87if ((LowInsn & 0xf800) != 0xf800)88return make_error<StringError>("Unrecognized thumb branch encoding "89"(BR22 low bits)",90inconvertibleErrorCode());9192return SignExtend64<23>(((HighInsn & 0x7ff) << 12) |93((LowInsn & 0x7ff) << 1));94}95}96}9798Expected<relocation_iterator>99processRelocationRef(unsigned SectionID, relocation_iterator RelI,100const ObjectFile &BaseObjT,101ObjSectionToIDMap &ObjSectionToID,102StubMap &Stubs) override {103const MachOObjectFile &Obj =104static_cast<const MachOObjectFile &>(BaseObjT);105MachO::any_relocation_info RelInfo =106Obj.getRelocation(RelI->getRawDataRefImpl());107uint32_t RelType = Obj.getAnyRelocationType(RelInfo);108109// Set to true for thumb functions in this (or previous) TUs.110// Will be used to set the TargetIsThumbFunc member on the relocation entry.111bool TargetIsLocalThumbFunc = false;112if (Obj.getPlainRelocationExternal(RelInfo)) {113auto Symbol = RelI->getSymbol();114StringRef TargetName;115if (auto TargetNameOrErr = Symbol->getName())116TargetName = *TargetNameOrErr;117else118return TargetNameOrErr.takeError();119120// If the target is external but the value doesn't have a name then we've121// converted the value to a section/offset pair, but we still need to set122// the IsTargetThumbFunc bit, so look the value up in the globla symbol table.123auto EntryItr = GlobalSymbolTable.find(TargetName);124if (EntryItr != GlobalSymbolTable.end()) {125TargetIsLocalThumbFunc =126EntryItr->second.getFlags().getTargetFlags() &127ARMJITSymbolFlags::Thumb;128}129}130131if (Obj.isRelocationScattered(RelInfo)) {132if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)133return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,134ObjSectionToID);135else if (RelType == MachO::GENERIC_RELOC_VANILLA)136return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,137TargetIsLocalThumbFunc);138else139return ++RelI;140}141142// Validate the relocation type.143switch (RelType) {144UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);145UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);146UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);147UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);148UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);149UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);150default:151if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)152return make_error<RuntimeDyldError>(("MachO ARM relocation type " +153Twine(RelType) +154" is out of range").str());155break;156}157158RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));159if (auto AddendOrErr = decodeAddend(RE))160RE.Addend = *AddendOrErr;161else162return AddendOrErr.takeError();163RE.IsTargetThumbFunc = TargetIsLocalThumbFunc;164165RelocationValueRef Value;166if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))167Value = *ValueOrErr;168else169return ValueOrErr.takeError();170171// If this is a branch from a thumb function (BR22) then make sure we mark172// the value as being a thumb stub: we don't want to mix it up with an ARM173// stub targeting the same function.174if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)175Value.IsStubThumb = true;176177if (RE.IsPCRel)178makeValueAddendPCRel(Value, RelI,179(RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);180181// If this is a non-external branch target check whether Value points to a182// thumb func.183if (!Value.SymbolName && (RelType == MachO::ARM_RELOC_BR24 ||184RelType == MachO::ARM_THUMB_RELOC_BR22))185RE.IsTargetThumbFunc = isAddrTargetThumb(Value.SectionID, Value.Offset);186187if (RE.RelType == MachO::ARM_RELOC_BR24 ||188RE.RelType == MachO::ARM_THUMB_RELOC_BR22)189processBranchRelocation(RE, Value, Stubs);190else {191RE.Addend = Value.Offset;192if (Value.SymbolName)193addRelocationForSymbol(RE, Value.SymbolName);194else195addRelocationForSection(RE, Value.SectionID);196}197198return ++RelI;199}200201void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {202LLVM_DEBUG(dumpRelocationToResolve(RE, Value));203const SectionEntry &Section = Sections[RE.SectionID];204uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);205206// If the relocation is PC-relative, the value to be encoded is the207// pointer difference.208if (RE.IsPCRel) {209uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);210Value -= FinalAddress;211// ARM PCRel relocations have an effective-PC offset of two instructions212// (four bytes in Thumb mode, 8 bytes in ARM mode).213Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;214}215216switch (RE.RelType) {217case MachO::ARM_THUMB_RELOC_BR22: {218Value += RE.Addend;219uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);220assert((HighInsn & 0xf800) == 0xf000 &&221"Unrecognized thumb branch encoding (BR22 high bits)");222HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff);223224uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);225assert((LowInsn & 0xf800) == 0xf800 &&226"Unrecognized thumb branch encoding (BR22 low bits)");227LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff);228229writeBytesUnaligned(HighInsn, LocalAddress, 2);230writeBytesUnaligned(LowInsn, LocalAddress + 2, 2);231break;232}233234case MachO::ARM_RELOC_VANILLA:235if (RE.IsTargetThumbFunc)236Value |= 0x01;237writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);238break;239case MachO::ARM_RELOC_BR24: {240// Mask the value into the target address. We know instructions are241// 32-bit aligned, so we can do it all at once.242Value += RE.Addend;243// The low two bits of the value are not encoded.244Value >>= 2;245// Mask the value to 24 bits.246uint64_t FinalValue = Value & 0xffffff;247// FIXME: If the destination is a Thumb function (and the instruction248// is a non-predicated BL instruction), we need to change it to a BLX249// instruction instead.250251// Insert the value into the instruction.252uint32_t Temp = readBytesUnaligned(LocalAddress, 4);253writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);254255break;256}257case MachO::ARM_RELOC_HALF_SECTDIFF: {258uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();259uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();260assert((Value == SectionABase || Value == SectionBBase) &&261"Unexpected HALFSECTDIFF relocation value.");262Value = SectionABase - SectionBBase + RE.Addend;263if (RE.Size & 0x1) // :upper16:264Value = (Value >> 16);265266bool IsThumb = RE.Size & 0x2;267268Value &= 0xffff;269270uint32_t Insn = readBytesUnaligned(LocalAddress, 4);271272if (IsThumb)273Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) |274((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) |275((Value & 0x00ff) << 16);276else277Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);278writeBytesUnaligned(Insn, LocalAddress, 4);279break;280}281282default:283llvm_unreachable("Invalid relocation type");284}285}286287Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,288const SectionRef &Section) {289StringRef Name;290if (Expected<StringRef> NameOrErr = Section.getName())291Name = *NameOrErr;292else293consumeError(NameOrErr.takeError());294295if (Name == "__nl_symbol_ptr")296return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),297Section, SectionID);298return Error::success();299}300301private:302303void processBranchRelocation(const RelocationEntry &RE,304const RelocationValueRef &Value,305StubMap &Stubs) {306// This is an ARM branch relocation, need to use a stub function.307// Look up for existing stub.308SectionEntry &Section = Sections[RE.SectionID];309RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);310uint8_t *Addr;311if (i != Stubs.end()) {312Addr = Section.getAddressWithOffset(i->second);313} else {314// Create a new stub function.315assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");316Stubs[Value] = Section.getStubOffset();317uint32_t StubOpcode = 0;318if (RE.RelType == MachO::ARM_RELOC_BR24)319StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4]320else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)321StubOpcode = 0xf000f8df; // ldr pc, [pc]322else323llvm_unreachable("Unrecognized relocation");324Addr = Section.getAddressWithOffset(Section.getStubOffset());325writeBytesUnaligned(StubOpcode, Addr, 4);326uint8_t *StubTargetAddr = Addr + 4;327RelocationEntry StubRE(328RE.SectionID, StubTargetAddr - Section.getAddress(),329MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);330StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;331if (Value.SymbolName)332addRelocationForSymbol(StubRE, Value.SymbolName);333else334addRelocationForSection(StubRE, Value.SectionID);335Section.advanceStubOffset(getMaxStubSize());336}337RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,338RE.IsPCRel, RE.Size);339resolveRelocation(TargetRE, (uint64_t)Addr);340}341342Expected<relocation_iterator>343processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,344const ObjectFile &BaseTObj,345ObjSectionToIDMap &ObjSectionToID) {346const MachOObjectFile &MachO =347static_cast<const MachOObjectFile&>(BaseTObj);348MachO::any_relocation_info RE =349MachO.getRelocation(RelI->getRawDataRefImpl());350351// For a half-diff relocation the length bits actually record whether this352// is a movw/movt, and whether this is arm or thumb.353// Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).354// Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).355unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);356bool IsThumb = HalfDiffKindBits & 0x2;357358SectionEntry &Section = Sections[SectionID];359uint32_t RelocType = MachO.getAnyRelocationType(RE);360bool IsPCRel = MachO.getAnyRelocationPCRel(RE);361uint64_t Offset = RelI->getOffset();362uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);363int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.364365if (IsThumb)366Immediate = ((Immediate & 0x0000000f) << 12) |367((Immediate & 0x00000400) << 1) |368((Immediate & 0x70000000) >> 20) |369((Immediate & 0x00ff0000) >> 16);370else371Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);372373++RelI;374MachO::any_relocation_info RE2 =375MachO.getRelocation(RelI->getRawDataRefImpl());376uint32_t AddrA = MachO.getScatteredRelocationValue(RE);377section_iterator SAI = getSectionByAddress(MachO, AddrA);378assert(SAI != MachO.section_end() && "Can't find section for address A");379uint64_t SectionABase = SAI->getAddress();380uint64_t SectionAOffset = AddrA - SectionABase;381SectionRef SectionA = *SAI;382bool IsCode = SectionA.isText();383uint32_t SectionAID = ~0U;384if (auto SectionAIDOrErr =385findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))386SectionAID = *SectionAIDOrErr;387else388return SectionAIDOrErr.takeError();389390uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);391section_iterator SBI = getSectionByAddress(MachO, AddrB);392assert(SBI != MachO.section_end() && "Can't find section for address B");393uint64_t SectionBBase = SBI->getAddress();394uint64_t SectionBOffset = AddrB - SectionBBase;395SectionRef SectionB = *SBI;396uint32_t SectionBID = ~0U;397if (auto SectionBIDOrErr =398findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))399SectionBID = *SectionBIDOrErr;400else401return SectionBIDOrErr.takeError();402403uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;404unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;405uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));406int64_t Addend = FullImmVal - (AddrA - AddrB);407408// addend = Encoded - Expected409// = Encoded - (AddrA - AddrB)410411LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA412<< ", AddrB: " << AddrB << ", Addend: " << Addend413<< ", SectionA ID: " << SectionAID << ", SectionAOffset: "414<< SectionAOffset << ", SectionB ID: " << SectionBID415<< ", SectionBOffset: " << SectionBOffset << "\n");416RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,417SectionAOffset, SectionBID, SectionBOffset, IsPCRel,418HalfDiffKindBits);419420addRelocationForSection(R, SectionAID);421422return ++RelI;423}424425};426}427428#undef DEBUG_TYPE429430#endif431432433