1 //===- ARM.cpp ------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "InputFiles.h" 10 #include "Symbols.h" 11 #include "SyntheticSections.h" 12 #include "Target.h" 13 14 #include "lld/Common/ErrorHandler.h" 15 #include "llvm/ADT/Bitfields.h" 16 #include "llvm/BinaryFormat/MachO.h" 17 #include "llvm/Support/Endian.h" 18 19 using namespace llvm; 20 using namespace llvm::MachO; 21 using namespace llvm::support::endian; 22 using namespace lld; 23 using namespace lld::macho; 24 25 namespace { 26 27 struct ARM : TargetInfo { 28 ARM(uint32_t cpuSubtype); 29 30 int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, 31 const relocation_info) const override; 32 void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, 33 uint64_t pc) const override; 34 35 void writeStub(uint8_t *buf, const Symbol &) const override; 36 void writeStubHelperHeader(uint8_t *buf) const override; 37 void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &, 38 uint64_t entryAddr) const override; 39 40 void relaxGotLoad(uint8_t *loc, uint8_t type) const override; 41 const RelocAttrs &getRelocAttrs(uint8_t type) const override; 42 uint64_t getPageSize() const override { return 4 * 1024; } 43 }; 44 45 } // namespace 46 47 const RelocAttrs &ARM::getRelocAttrs(uint8_t type) const { 48 static const std::array<RelocAttrs, 10> relocAttrsArray{{ 49 #define B(x) RelocAttrBits::x 50 {"VANILLA", /* FIXME populate this */ B(_0)}, 51 {"PAIR", /* FIXME populate this */ B(_0)}, 52 {"SECTDIFF", /* FIXME populate this */ B(_0)}, 53 {"LOCAL_SECTDIFF", /* FIXME populate this */ B(_0)}, 54 {"PB_LA_PTR", /* FIXME populate this */ B(_0)}, 55 {"BR24", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, 56 {"BR22", B(PCREL) | B(LOCAL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, 57 {"32BIT_BRANCH", /* FIXME populate this */ B(_0)}, 58 {"HALF", /* FIXME populate this */ B(_0)}, 59 {"HALF_SECTDIFF", /* FIXME populate this */ B(_0)}, 60 #undef B 61 }}; 62 assert(type < relocAttrsArray.size() && "invalid relocation type"); 63 if (type >= relocAttrsArray.size()) 64 return invalidRelocAttrs; 65 return relocAttrsArray[type]; 66 } 67 68 int64_t ARM::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, 69 relocation_info rel) const { 70 // FIXME: implement this 71 return 0; 72 } 73 74 template <int N> using BitfieldFlag = Bitfield::Element<bool, N, 1>; 75 76 // ARM BL encoding: 77 // 78 // 30 28 24 0 79 // +---------+---------+----------------------------------------------+ 80 // | cond | 1 0 1 1 | imm24 | 81 // +---------+---------+----------------------------------------------+ 82 // 83 // `cond` here varies depending on whether we have bleq, blne, etc. 84 // `imm24` encodes a 26-bit pcrel offset -- last 2 bits are zero as ARM 85 // functions are 4-byte-aligned. 86 // 87 // ARM BLX encoding: 88 // 89 // 30 28 24 0 90 // +---------+---------+----------------------------------------------+ 91 // | 1 1 1 1 | 1 0 1 H | imm24 | 92 // +---------+---------+----------------------------------------------+ 93 // 94 // Since Thumb functions are 2-byte-aligned, we need one extra bit to encode 95 // the offset -- that is the H bit. 96 // 97 // BLX is always unconditional, so while we can convert directly from BLX to BL, 98 // we need to insert a shim if a BL's target is a Thumb function. 99 // 100 // Helper aliases for decoding BL / BLX: 101 using Cond = Bitfield::Element<uint32_t, 28, 4>; 102 using Imm24 = Bitfield::Element<int32_t, 0, 24>; 103 104 void ARM::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value, 105 uint64_t pc) const { 106 switch (r.type) { 107 case ARM_RELOC_BR24: { 108 uint32_t base = read32le(loc); 109 bool isBlx = Bitfield::get<Cond>(base) == 0xf; 110 const Symbol *sym = r.referent.get<Symbol *>(); 111 int32_t offset = value - (pc + 8); 112 113 if (auto *defined = dyn_cast<Defined>(sym)) { 114 if (!isBlx && defined->thumb) { 115 error("TODO: implement interworking shim"); 116 return; 117 } else if (isBlx && !defined->thumb) { 118 Bitfield::set<Cond>(base, 0xe); // unconditional BL 119 Bitfield::set<BitfieldFlag<24>>(base, 1); 120 isBlx = false; 121 } 122 } else { 123 error("TODO: Implement ARM_RELOC_BR24 for dylib symbols"); 124 return; 125 } 126 127 if (isBlx) { 128 assert((0x1 & value) == 0); 129 Bitfield::set<Imm24>(base, offset >> 2); 130 Bitfield::set<BitfieldFlag<24>>(base, (offset >> 1) & 1); // H bit 131 } else { 132 assert((0x3 & value) == 0); 133 Bitfield::set<Imm24>(base, offset >> 2); 134 } 135 write32le(loc, base); 136 break; 137 } 138 default: 139 fatal("unhandled relocation type"); 140 } 141 } 142 143 void ARM::writeStub(uint8_t *buf, const Symbol &sym) const { 144 fatal("TODO: implement this"); 145 } 146 147 void ARM::writeStubHelperHeader(uint8_t *buf) const { 148 fatal("TODO: implement this"); 149 } 150 151 void ARM::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym, 152 uint64_t entryAddr) const { 153 fatal("TODO: implement this"); 154 } 155 156 void ARM::relaxGotLoad(uint8_t *loc, uint8_t type) const { 157 fatal("TODO: implement this"); 158 } 159 160 ARM::ARM(uint32_t cpuSubtype) : TargetInfo(ILP32()) { 161 cpuType = CPU_TYPE_ARM; 162 this->cpuSubtype = cpuSubtype; 163 164 stubSize = 0 /* FIXME */; 165 stubHelperHeaderSize = 0 /* FIXME */; 166 stubHelperEntrySize = 0 /* FIXME */; 167 } 168 169 TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) { 170 static ARM t(cpuSubtype); 171 return &t; 172 } 173