xref: /openbsd-src/gnu/llvm/lld/MachO/Arch/ARM.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
11cf9926bSpatrick //===- ARM.cpp ------------------------------------------------------------===//
21cf9926bSpatrick //
31cf9926bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41cf9926bSpatrick // See https://llvm.org/LICENSE.txt for license information.
51cf9926bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61cf9926bSpatrick //
71cf9926bSpatrick //===----------------------------------------------------------------------===//
81cf9926bSpatrick 
91cf9926bSpatrick #include "InputFiles.h"
101cf9926bSpatrick #include "Symbols.h"
111cf9926bSpatrick #include "SyntheticSections.h"
121cf9926bSpatrick #include "Target.h"
131cf9926bSpatrick 
141cf9926bSpatrick #include "lld/Common/ErrorHandler.h"
151cf9926bSpatrick #include "llvm/ADT/Bitfields.h"
161cf9926bSpatrick #include "llvm/BinaryFormat/MachO.h"
171cf9926bSpatrick #include "llvm/Support/Endian.h"
181cf9926bSpatrick 
191cf9926bSpatrick using namespace llvm;
201cf9926bSpatrick using namespace llvm::MachO;
211cf9926bSpatrick using namespace llvm::support::endian;
221cf9926bSpatrick using namespace lld;
231cf9926bSpatrick using namespace lld::macho;
241cf9926bSpatrick 
251cf9926bSpatrick namespace {
261cf9926bSpatrick 
271cf9926bSpatrick struct ARM : TargetInfo {
281cf9926bSpatrick   ARM(uint32_t cpuSubtype);
291cf9926bSpatrick 
301cf9926bSpatrick   int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset,
311cf9926bSpatrick                             const relocation_info) const override;
321cf9926bSpatrick   void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
331cf9926bSpatrick                    uint64_t pc) const override;
341cf9926bSpatrick 
35*dfe94b16Srobert   void writeStub(uint8_t *buf, const Symbol &, uint64_t) const override;
361cf9926bSpatrick   void writeStubHelperHeader(uint8_t *buf) const override;
37*dfe94b16Srobert   void writeStubHelperEntry(uint8_t *buf, const Symbol &,
381cf9926bSpatrick                             uint64_t entryAddr) const override;
391cf9926bSpatrick 
40*dfe94b16Srobert   void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
41*dfe94b16Srobert                             uint64_t stubOffset, uint64_t selrefsVA,
42*dfe94b16Srobert                             uint64_t selectorIndex, uint64_t gotAddr,
43*dfe94b16Srobert                             uint64_t msgSendIndex) const override;
441cf9926bSpatrick 
45*dfe94b16Srobert   void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
getPageSize__anon504094860111::ARM46*dfe94b16Srobert   uint64_t getPageSize() const override { return 4 * 1024; }
47*dfe94b16Srobert 
48*dfe94b16Srobert   void handleDtraceReloc(const Symbol *sym, const Reloc &r,
49*dfe94b16Srobert                          uint8_t *loc) const override;
50*dfe94b16Srobert };
511cf9926bSpatrick } // namespace
521cf9926bSpatrick 
53*dfe94b16Srobert static constexpr std::array<RelocAttrs, 10> relocAttrsArray{{
541cf9926bSpatrick #define B(x) RelocAttrBits::x
551cf9926bSpatrick     {"VANILLA", /* FIXME populate this */ B(_0)},
561cf9926bSpatrick     {"PAIR", /* FIXME populate this */ B(_0)},
571cf9926bSpatrick     {"SECTDIFF", /* FIXME populate this */ B(_0)},
581cf9926bSpatrick     {"LOCAL_SECTDIFF", /* FIXME populate this */ B(_0)},
591cf9926bSpatrick     {"PB_LA_PTR", /* FIXME populate this */ B(_0)},
601cf9926bSpatrick     {"BR24", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
611cf9926bSpatrick     {"BR22", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
621cf9926bSpatrick     {"32BIT_BRANCH", /* FIXME populate this */ B(_0)},
631cf9926bSpatrick     {"HALF", /* FIXME populate this */ B(_0)},
641cf9926bSpatrick     {"HALF_SECTDIFF", /* FIXME populate this */ B(_0)},
651cf9926bSpatrick #undef B
661cf9926bSpatrick }};
671cf9926bSpatrick 
getEmbeddedAddend(MemoryBufferRef mb,uint64_t offset,relocation_info rel) const681cf9926bSpatrick int64_t ARM::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
691cf9926bSpatrick                                relocation_info rel) const {
701cf9926bSpatrick   // FIXME: implement this
711cf9926bSpatrick   return 0;
721cf9926bSpatrick }
731cf9926bSpatrick 
741cf9926bSpatrick template <int N> using BitfieldFlag = Bitfield::Element<bool, N, 1>;
751cf9926bSpatrick 
761cf9926bSpatrick // ARM BL encoding:
771cf9926bSpatrick //
781cf9926bSpatrick // 30       28        24                                              0
791cf9926bSpatrick // +---------+---------+----------------------------------------------+
801cf9926bSpatrick // |  cond   | 1 0 1 1 |                  imm24                       |
811cf9926bSpatrick // +---------+---------+----------------------------------------------+
821cf9926bSpatrick //
831cf9926bSpatrick // `cond` here varies depending on whether we have bleq, blne, etc.
841cf9926bSpatrick // `imm24` encodes a 26-bit pcrel offset -- last 2 bits are zero as ARM
851cf9926bSpatrick // functions are 4-byte-aligned.
861cf9926bSpatrick //
871cf9926bSpatrick // ARM BLX encoding:
881cf9926bSpatrick //
891cf9926bSpatrick // 30       28        24                                              0
901cf9926bSpatrick // +---------+---------+----------------------------------------------+
911cf9926bSpatrick // | 1 1 1 1 | 1 0 1 H |                  imm24                       |
921cf9926bSpatrick // +---------+---------+----------------------------------------------+
931cf9926bSpatrick //
941cf9926bSpatrick // Since Thumb functions are 2-byte-aligned, we need one extra bit to encode
951cf9926bSpatrick // the offset -- that is the H bit.
961cf9926bSpatrick //
971cf9926bSpatrick // BLX is always unconditional, so while we can convert directly from BLX to BL,
981cf9926bSpatrick // we need to insert a shim if a BL's target is a Thumb function.
991cf9926bSpatrick //
1001cf9926bSpatrick // Helper aliases for decoding BL / BLX:
1011cf9926bSpatrick using Cond = Bitfield::Element<uint32_t, 28, 4>;
1021cf9926bSpatrick using Imm24 = Bitfield::Element<int32_t, 0, 24>;
1031cf9926bSpatrick 
relocateOne(uint8_t * loc,const Reloc & r,uint64_t value,uint64_t pc) const1041cf9926bSpatrick void ARM::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
1051cf9926bSpatrick                       uint64_t pc) const {
1061cf9926bSpatrick   switch (r.type) {
1071cf9926bSpatrick   case ARM_RELOC_BR24: {
1081cf9926bSpatrick     uint32_t base = read32le(loc);
1091cf9926bSpatrick     bool isBlx = Bitfield::get<Cond>(base) == 0xf;
1101cf9926bSpatrick     const Symbol *sym = r.referent.get<Symbol *>();
1111cf9926bSpatrick     int32_t offset = value - (pc + 8);
1121cf9926bSpatrick 
1131cf9926bSpatrick     if (auto *defined = dyn_cast<Defined>(sym)) {
1141cf9926bSpatrick       if (!isBlx && defined->thumb) {
1151cf9926bSpatrick         error("TODO: implement interworking shim");
1161cf9926bSpatrick         return;
1171cf9926bSpatrick       } else if (isBlx && !defined->thumb) {
1181cf9926bSpatrick         Bitfield::set<Cond>(base, 0xe); // unconditional BL
119*dfe94b16Srobert         Bitfield::set<BitfieldFlag<24>>(base, true);
1201cf9926bSpatrick         isBlx = false;
1211cf9926bSpatrick       }
1221cf9926bSpatrick     } else {
1231cf9926bSpatrick       error("TODO: Implement ARM_RELOC_BR24 for dylib symbols");
1241cf9926bSpatrick       return;
1251cf9926bSpatrick     }
1261cf9926bSpatrick 
1271cf9926bSpatrick     if (isBlx) {
1281cf9926bSpatrick       assert((0x1 & value) == 0);
1291cf9926bSpatrick       Bitfield::set<Imm24>(base, offset >> 2);
1301cf9926bSpatrick       Bitfield::set<BitfieldFlag<24>>(base, (offset >> 1) & 1); // H bit
1311cf9926bSpatrick     } else {
1321cf9926bSpatrick       assert((0x3 & value) == 0);
1331cf9926bSpatrick       Bitfield::set<Imm24>(base, offset >> 2);
1341cf9926bSpatrick     }
1351cf9926bSpatrick     write32le(loc, base);
1361cf9926bSpatrick     break;
1371cf9926bSpatrick   }
1381cf9926bSpatrick   default:
1391cf9926bSpatrick     fatal("unhandled relocation type");
1401cf9926bSpatrick   }
1411cf9926bSpatrick }
1421cf9926bSpatrick 
writeStub(uint8_t * buf,const Symbol & sym,uint64_t) const143*dfe94b16Srobert void ARM::writeStub(uint8_t *buf, const Symbol &sym, uint64_t) const {
1441cf9926bSpatrick   fatal("TODO: implement this");
1451cf9926bSpatrick }
1461cf9926bSpatrick 
writeStubHelperHeader(uint8_t * buf) const1471cf9926bSpatrick void ARM::writeStubHelperHeader(uint8_t *buf) const {
1481cf9926bSpatrick   fatal("TODO: implement this");
1491cf9926bSpatrick }
1501cf9926bSpatrick 
writeStubHelperEntry(uint8_t * buf,const Symbol & sym,uint64_t entryAddr) const151*dfe94b16Srobert void ARM::writeStubHelperEntry(uint8_t *buf, const Symbol &sym,
1521cf9926bSpatrick                                uint64_t entryAddr) const {
1531cf9926bSpatrick   fatal("TODO: implement this");
1541cf9926bSpatrick }
1551cf9926bSpatrick 
writeObjCMsgSendStub(uint8_t * buf,Symbol * sym,uint64_t stubsAddr,uint64_t stubOffset,uint64_t selrefsVA,uint64_t selectorIndex,uint64_t gotAddr,uint64_t msgSendIndex) const156*dfe94b16Srobert void ARM::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
157*dfe94b16Srobert                                uint64_t stubOffset, uint64_t selrefsVA,
158*dfe94b16Srobert                                uint64_t selectorIndex, uint64_t gotAddr,
159*dfe94b16Srobert                                uint64_t msgSendIndex) const {
160*dfe94b16Srobert   fatal("TODO: implement this");
161*dfe94b16Srobert }
162*dfe94b16Srobert 
relaxGotLoad(uint8_t * loc,uint8_t type) const1631cf9926bSpatrick void ARM::relaxGotLoad(uint8_t *loc, uint8_t type) const {
1641cf9926bSpatrick   fatal("TODO: implement this");
1651cf9926bSpatrick }
1661cf9926bSpatrick 
ARM(uint32_t cpuSubtype)1671cf9926bSpatrick ARM::ARM(uint32_t cpuSubtype) : TargetInfo(ILP32()) {
1681cf9926bSpatrick   cpuType = CPU_TYPE_ARM;
1691cf9926bSpatrick   this->cpuSubtype = cpuSubtype;
1701cf9926bSpatrick 
1711cf9926bSpatrick   stubSize = 0 /* FIXME */;
1721cf9926bSpatrick   stubHelperHeaderSize = 0 /* FIXME */;
1731cf9926bSpatrick   stubHelperEntrySize = 0 /* FIXME */;
174*dfe94b16Srobert 
175*dfe94b16Srobert   relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};
1761cf9926bSpatrick }
1771cf9926bSpatrick 
createARMTargetInfo(uint32_t cpuSubtype)1781cf9926bSpatrick TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) {
1791cf9926bSpatrick   static ARM t(cpuSubtype);
1801cf9926bSpatrick   return &t;
1811cf9926bSpatrick }
182*dfe94b16Srobert 
handleDtraceReloc(const Symbol * sym,const Reloc & r,uint8_t * loc) const183*dfe94b16Srobert void ARM::handleDtraceReloc(const Symbol *sym, const Reloc &r,
184*dfe94b16Srobert                             uint8_t *loc) const {
185*dfe94b16Srobert   if (config->outputType == MH_OBJECT)
186*dfe94b16Srobert     return;
187*dfe94b16Srobert 
188*dfe94b16Srobert   switch (r.type) {
189*dfe94b16Srobert   case ARM_RELOC_BR24:
190*dfe94b16Srobert     if (sym->getName().startswith("___dtrace_probe")) {
191*dfe94b16Srobert       // change call site to a NOP
192*dfe94b16Srobert       write32le(loc, 0xE1A00000);
193*dfe94b16Srobert     } else if (sym->getName().startswith("___dtrace_isenabled")) {
194*dfe94b16Srobert       // change call site to 'eor r0, r0, r0'
195*dfe94b16Srobert       write32le(loc, 0xE0200000);
196*dfe94b16Srobert     } else {
197*dfe94b16Srobert       error("Unrecognized dtrace symbol prefix: " + toString(*sym));
198*dfe94b16Srobert     }
199*dfe94b16Srobert     break;
200*dfe94b16Srobert   case ARM_THUMB_RELOC_BR22:
201*dfe94b16Srobert     if (sym->getName().startswith("___dtrace_probe")) {
202*dfe94b16Srobert       // change 32-bit blx call site to two thumb NOPs
203*dfe94b16Srobert       write32le(loc, 0x46C046C0);
204*dfe94b16Srobert     } else if (sym->getName().startswith("___dtrace_isenabled")) {
205*dfe94b16Srobert       // change 32-bit blx call site to 'nop', 'eor r0, r0'
206*dfe94b16Srobert       write32le(loc, 0x46C04040);
207*dfe94b16Srobert     } else {
208*dfe94b16Srobert       error("Unrecognized dtrace symbol prefix: " + toString(*sym));
209*dfe94b16Srobert     }
210*dfe94b16Srobert     break;
211*dfe94b16Srobert   default:
212*dfe94b16Srobert     llvm_unreachable("Unsupported dtrace relocation type for ARM");
213*dfe94b16Srobert   }
214*dfe94b16Srobert }
215