[LLD][COFF] Ignore DEBUG_S_XFGHASH_TYPE/VIRTUAL
[llvm-project.git] / lld / MachO / Arch / ARM.cpp
blob424df414229f356c3e8525261f81c566c463454c
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 //===----------------------------------------------------------------------===//
9 #include "InputFiles.h"
10 #include "Symbols.h"
11 #include "SyntheticSections.h"
12 #include "Target.h"
14 #include "lld/Common/ErrorHandler.h"
15 #include "llvm/ADT/Bitfields.h"
16 #include "llvm/BinaryFormat/MachO.h"
17 #include "llvm/Support/Endian.h"
19 using namespace llvm;
20 using namespace llvm::MachO;
21 using namespace llvm::support::endian;
22 using namespace lld;
23 using namespace lld::macho;
25 namespace {
27 struct ARM : TargetInfo {
28 ARM(uint32_t cpuSubtype);
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;
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 Symbol &,
38 uint64_t entryAddr) const override;
40 void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
41 uint64_t getPageSize() const override { return 4 * 1024; }
43 void handleDtraceReloc(const Symbol *sym, const Reloc &r,
44 uint8_t *loc) const override;
46 } // namespace
48 static constexpr 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 }};
63 int64_t ARM::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
64 relocation_info rel) const {
65 // FIXME: implement this
66 return 0;
69 template <int N> using BitfieldFlag = Bitfield::Element<bool, N, 1>;
71 // ARM BL encoding:
73 // 30 28 24 0
74 // +---------+---------+----------------------------------------------+
75 // | cond | 1 0 1 1 | imm24 |
76 // +---------+---------+----------------------------------------------+
78 // `cond` here varies depending on whether we have bleq, blne, etc.
79 // `imm24` encodes a 26-bit pcrel offset -- last 2 bits are zero as ARM
80 // functions are 4-byte-aligned.
82 // ARM BLX encoding:
84 // 30 28 24 0
85 // +---------+---------+----------------------------------------------+
86 // | 1 1 1 1 | 1 0 1 H | imm24 |
87 // +---------+---------+----------------------------------------------+
89 // Since Thumb functions are 2-byte-aligned, we need one extra bit to encode
90 // the offset -- that is the H bit.
92 // BLX is always unconditional, so while we can convert directly from BLX to BL,
93 // we need to insert a shim if a BL's target is a Thumb function.
95 // Helper aliases for decoding BL / BLX:
96 using Cond = Bitfield::Element<uint32_t, 28, 4>;
97 using Imm24 = Bitfield::Element<int32_t, 0, 24>;
99 void ARM::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
100 uint64_t pc) const {
101 switch (r.type) {
102 case ARM_RELOC_BR24: {
103 uint32_t base = read32le(loc);
104 bool isBlx = Bitfield::get<Cond>(base) == 0xf;
105 const Symbol *sym = r.referent.get<Symbol *>();
106 int32_t offset = value - (pc + 8);
108 if (auto *defined = dyn_cast<Defined>(sym)) {
109 if (!isBlx && defined->thumb) {
110 error("TODO: implement interworking shim");
111 return;
112 } else if (isBlx && !defined->thumb) {
113 Bitfield::set<Cond>(base, 0xe); // unconditional BL
114 Bitfield::set<BitfieldFlag<24>>(base, true);
115 isBlx = false;
117 } else {
118 error("TODO: Implement ARM_RELOC_BR24 for dylib symbols");
119 return;
122 if (isBlx) {
123 assert((0x1 & value) == 0);
124 Bitfield::set<Imm24>(base, offset >> 2);
125 Bitfield::set<BitfieldFlag<24>>(base, (offset >> 1) & 1); // H bit
126 } else {
127 assert((0x3 & value) == 0);
128 Bitfield::set<Imm24>(base, offset >> 2);
130 write32le(loc, base);
131 break;
133 default:
134 fatal("unhandled relocation type");
138 void ARM::writeStub(uint8_t *buf, const Symbol &sym) const {
139 fatal("TODO: implement this");
142 void ARM::writeStubHelperHeader(uint8_t *buf) const {
143 fatal("TODO: implement this");
146 void ARM::writeStubHelperEntry(uint8_t *buf, const Symbol &sym,
147 uint64_t entryAddr) const {
148 fatal("TODO: implement this");
151 void ARM::relaxGotLoad(uint8_t *loc, uint8_t type) const {
152 fatal("TODO: implement this");
155 ARM::ARM(uint32_t cpuSubtype) : TargetInfo(ILP32()) {
156 cpuType = CPU_TYPE_ARM;
157 this->cpuSubtype = cpuSubtype;
159 stubSize = 0 /* FIXME */;
160 stubHelperHeaderSize = 0 /* FIXME */;
161 stubHelperEntrySize = 0 /* FIXME */;
163 relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};
166 TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) {
167 static ARM t(cpuSubtype);
168 return &t;
171 void ARM::handleDtraceReloc(const Symbol *sym, const Reloc &r,
172 uint8_t *loc) const {
173 if (config->outputType == MH_OBJECT)
174 return;
176 switch (r.type) {
177 case ARM_RELOC_BR24:
178 if (sym->getName().startswith("___dtrace_probe")) {
179 // change call site to a NOP
180 write32le(loc, 0xE1A00000);
181 } else if (sym->getName().startswith("___dtrace_isenabled")) {
182 // change call site to 'eor r0, r0, r0'
183 write32le(loc, 0xE0200000);
184 } else {
185 error("Unrecognized dtrace symbol prefix: " + toString(*sym));
187 break;
188 case ARM_THUMB_RELOC_BR22:
189 if (sym->getName().startswith("___dtrace_probe")) {
190 // change 32-bit blx call site to two thumb NOPs
191 write32le(loc, 0x46C046C0);
192 } else if (sym->getName().startswith("___dtrace_isenabled")) {
193 // change 32-bit blx call site to 'nop', 'eor r0, r0'
194 write32le(loc, 0x46C04040);
195 } else {
196 error("Unrecognized dtrace symbol prefix: " + toString(*sym));
198 break;
199 default:
200 llvm_unreachable("Unsupported dtrace relocation type for ARM");