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::(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 | |