annotate lld/ELF/Thunks.cpp @ 213:25ca0248ac32

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sun, 11 Jul 2021 17:05:31 +0900
parents 2e18cbf3894f
children 5f17cb93ff66
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- Thunks.cpp --------------------------------------------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===---------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file contains Thunk subclasses.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 // A thunk is a small piece of code written after an input section
anatofuz
parents:
diff changeset
12 // which is used to jump between "incompatible" functions
anatofuz
parents:
diff changeset
13 // such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
anatofuz
parents:
diff changeset
14 //
anatofuz
parents:
diff changeset
15 // If a jump target is too far and its address doesn't fit to a
anatofuz
parents:
diff changeset
16 // short jump instruction, we need to create a thunk too, but we
anatofuz
parents:
diff changeset
17 // haven't supported it yet.
anatofuz
parents:
diff changeset
18 //
anatofuz
parents:
diff changeset
19 // i386 and x86-64 don't need thunks.
anatofuz
parents:
diff changeset
20 //
anatofuz
parents:
diff changeset
21 //===---------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
22
anatofuz
parents:
diff changeset
23 #include "Thunks.h"
anatofuz
parents:
diff changeset
24 #include "Config.h"
anatofuz
parents:
diff changeset
25 #include "InputSection.h"
anatofuz
parents:
diff changeset
26 #include "OutputSections.h"
anatofuz
parents:
diff changeset
27 #include "Symbols.h"
anatofuz
parents:
diff changeset
28 #include "SyntheticSections.h"
anatofuz
parents:
diff changeset
29 #include "Target.h"
anatofuz
parents:
diff changeset
30 #include "lld/Common/ErrorHandler.h"
anatofuz
parents:
diff changeset
31 #include "lld/Common/Memory.h"
anatofuz
parents:
diff changeset
32 #include "llvm/BinaryFormat/ELF.h"
anatofuz
parents:
diff changeset
33 #include "llvm/Support/Casting.h"
anatofuz
parents:
diff changeset
34 #include "llvm/Support/Endian.h"
anatofuz
parents:
diff changeset
35 #include "llvm/Support/ErrorHandling.h"
anatofuz
parents:
diff changeset
36 #include "llvm/Support/MathExtras.h"
anatofuz
parents:
diff changeset
37 #include <cstdint>
anatofuz
parents:
diff changeset
38 #include <cstring>
anatofuz
parents:
diff changeset
39
anatofuz
parents:
diff changeset
40 using namespace llvm;
anatofuz
parents:
diff changeset
41 using namespace llvm::object;
anatofuz
parents:
diff changeset
42 using namespace llvm::ELF;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
43 using namespace lld;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
44 using namespace lld::elf;
150
anatofuz
parents:
diff changeset
45
anatofuz
parents:
diff changeset
46 namespace {
anatofuz
parents:
diff changeset
47
anatofuz
parents:
diff changeset
48 // AArch64 long range Thunks
anatofuz
parents:
diff changeset
49 class AArch64ABSLongThunk final : public Thunk {
anatofuz
parents:
diff changeset
50 public:
anatofuz
parents:
diff changeset
51 AArch64ABSLongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
anatofuz
parents:
diff changeset
52 uint32_t size() override { return 16; }
anatofuz
parents:
diff changeset
53 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
54 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
55 };
anatofuz
parents:
diff changeset
56
anatofuz
parents:
diff changeset
57 class AArch64ADRPThunk final : public Thunk {
anatofuz
parents:
diff changeset
58 public:
anatofuz
parents:
diff changeset
59 AArch64ADRPThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
anatofuz
parents:
diff changeset
60 uint32_t size() override { return 12; }
anatofuz
parents:
diff changeset
61 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
62 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
63 };
anatofuz
parents:
diff changeset
64
anatofuz
parents:
diff changeset
65 // Base class for ARM thunks.
anatofuz
parents:
diff changeset
66 //
anatofuz
parents:
diff changeset
67 // An ARM thunk may be either short or long. A short thunk is simply a branch
anatofuz
parents:
diff changeset
68 // (B) instruction, and it may be used to call ARM functions when the distance
anatofuz
parents:
diff changeset
69 // from the thunk to the target is less than 32MB. Long thunks can branch to any
anatofuz
parents:
diff changeset
70 // virtual address and can switch between ARM and Thumb, and they are
anatofuz
parents:
diff changeset
71 // implemented in the derived classes. This class tries to create a short thunk
anatofuz
parents:
diff changeset
72 // if the target is in range, otherwise it creates a long thunk.
anatofuz
parents:
diff changeset
73 class ARMThunk : public Thunk {
anatofuz
parents:
diff changeset
74 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
75 ARMThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
76
anatofuz
parents:
diff changeset
77 bool getMayUseShortThunk();
anatofuz
parents:
diff changeset
78 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
anatofuz
parents:
diff changeset
79 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
80 bool isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
81 const Relocation &rel) const override;
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 // Returns the size of a long thunk.
anatofuz
parents:
diff changeset
84 virtual uint32_t sizeLong() = 0;
anatofuz
parents:
diff changeset
85
anatofuz
parents:
diff changeset
86 // Writes a long thunk to Buf.
anatofuz
parents:
diff changeset
87 virtual void writeLong(uint8_t *buf) = 0;
anatofuz
parents:
diff changeset
88
anatofuz
parents:
diff changeset
89 private:
anatofuz
parents:
diff changeset
90 // This field tracks whether all previously considered layouts would allow
anatofuz
parents:
diff changeset
91 // this thunk to be short. If we have ever needed a long thunk, we always
anatofuz
parents:
diff changeset
92 // create a long thunk, even if the thunk may be short given the current
anatofuz
parents:
diff changeset
93 // distance to the target. We do this because transitioning from long to short
anatofuz
parents:
diff changeset
94 // can create layout oscillations in certain corner cases which would prevent
anatofuz
parents:
diff changeset
95 // the layout from converging.
anatofuz
parents:
diff changeset
96 bool mayUseShortThunk = true;
anatofuz
parents:
diff changeset
97 };
anatofuz
parents:
diff changeset
98
anatofuz
parents:
diff changeset
99 // Base class for Thumb-2 thunks.
anatofuz
parents:
diff changeset
100 //
anatofuz
parents:
diff changeset
101 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
anatofuz
parents:
diff changeset
102 // which has a range of 16MB.
anatofuz
parents:
diff changeset
103 class ThumbThunk : public Thunk {
anatofuz
parents:
diff changeset
104 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
105 ThumbThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
106 alignment = 2;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
107 }
150
anatofuz
parents:
diff changeset
108
anatofuz
parents:
diff changeset
109 bool getMayUseShortThunk();
anatofuz
parents:
diff changeset
110 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
anatofuz
parents:
diff changeset
111 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
112 bool isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
113 const Relocation &rel) const override;
anatofuz
parents:
diff changeset
114
anatofuz
parents:
diff changeset
115 // Returns the size of a long thunk.
anatofuz
parents:
diff changeset
116 virtual uint32_t sizeLong() = 0;
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 // Writes a long thunk to Buf.
anatofuz
parents:
diff changeset
119 virtual void writeLong(uint8_t *buf) = 0;
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 private:
anatofuz
parents:
diff changeset
122 // See comment in ARMThunk above.
anatofuz
parents:
diff changeset
123 bool mayUseShortThunk = true;
anatofuz
parents:
diff changeset
124 };
anatofuz
parents:
diff changeset
125
anatofuz
parents:
diff changeset
126 // Specific ARM Thunk implementations. The naming convention is:
anatofuz
parents:
diff changeset
127 // Source State, TargetState, Target Requirement, ABS or PI, Range
anatofuz
parents:
diff changeset
128 class ARMV7ABSLongThunk final : public ARMThunk {
anatofuz
parents:
diff changeset
129 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
130 ARMV7ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
131
anatofuz
parents:
diff changeset
132 uint32_t sizeLong() override { return 12; }
anatofuz
parents:
diff changeset
133 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
134 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
135 };
anatofuz
parents:
diff changeset
136
anatofuz
parents:
diff changeset
137 class ARMV7PILongThunk final : public ARMThunk {
anatofuz
parents:
diff changeset
138 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
139 ARMV7PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
140
anatofuz
parents:
diff changeset
141 uint32_t sizeLong() override { return 16; }
anatofuz
parents:
diff changeset
142 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
143 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
144 };
anatofuz
parents:
diff changeset
145
anatofuz
parents:
diff changeset
146 class ThumbV7ABSLongThunk final : public ThumbThunk {
anatofuz
parents:
diff changeset
147 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
148 ThumbV7ABSLongThunk(Symbol &dest, int64_t addend)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
149 : ThumbThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
150
anatofuz
parents:
diff changeset
151 uint32_t sizeLong() override { return 10; }
anatofuz
parents:
diff changeset
152 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
153 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
154 };
anatofuz
parents:
diff changeset
155
anatofuz
parents:
diff changeset
156 class ThumbV7PILongThunk final : public ThumbThunk {
anatofuz
parents:
diff changeset
157 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
158 ThumbV7PILongThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
159
anatofuz
parents:
diff changeset
160 uint32_t sizeLong() override { return 12; }
anatofuz
parents:
diff changeset
161 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
162 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
163 };
anatofuz
parents:
diff changeset
164
anatofuz
parents:
diff changeset
165 // Implementations of Thunks for older Arm architectures that do not support
anatofuz
parents:
diff changeset
166 // the movt/movw instructions. These thunks require at least Architecture v5
anatofuz
parents:
diff changeset
167 // as used on processors such as the Arm926ej-s. There are no Thumb entry
anatofuz
parents:
diff changeset
168 // points as there is no Thumb branch instruction on these architecture that
anatofuz
parents:
diff changeset
169 // can result in a thunk
anatofuz
parents:
diff changeset
170 class ARMV5ABSLongThunk final : public ARMThunk {
anatofuz
parents:
diff changeset
171 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
172 ARMV5ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
173
anatofuz
parents:
diff changeset
174 uint32_t sizeLong() override { return 8; }
anatofuz
parents:
diff changeset
175 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
176 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
177 bool isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
178 const Relocation &rel) const override;
anatofuz
parents:
diff changeset
179 };
anatofuz
parents:
diff changeset
180
anatofuz
parents:
diff changeset
181 class ARMV5PILongThunk final : public ARMThunk {
anatofuz
parents:
diff changeset
182 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
183 ARMV5PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
184
anatofuz
parents:
diff changeset
185 uint32_t sizeLong() override { return 16; }
anatofuz
parents:
diff changeset
186 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
187 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
188 bool isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
189 const Relocation &rel) const override;
anatofuz
parents:
diff changeset
190 };
anatofuz
parents:
diff changeset
191
anatofuz
parents:
diff changeset
192 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
anatofuz
parents:
diff changeset
193 class ThumbV6MABSLongThunk final : public ThumbThunk {
anatofuz
parents:
diff changeset
194 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
195 ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
196 : ThumbThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
197
anatofuz
parents:
diff changeset
198 uint32_t sizeLong() override { return 12; }
anatofuz
parents:
diff changeset
199 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
200 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
201 };
anatofuz
parents:
diff changeset
202
anatofuz
parents:
diff changeset
203 class ThumbV6MPILongThunk final : public ThumbThunk {
anatofuz
parents:
diff changeset
204 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
205 ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
206 : ThumbThunk(dest, addend) {}
150
anatofuz
parents:
diff changeset
207
anatofuz
parents:
diff changeset
208 uint32_t sizeLong() override { return 16; }
anatofuz
parents:
diff changeset
209 void writeLong(uint8_t *buf) override;
anatofuz
parents:
diff changeset
210 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
211 };
anatofuz
parents:
diff changeset
212
anatofuz
parents:
diff changeset
213 // MIPS LA25 thunk
anatofuz
parents:
diff changeset
214 class MipsThunk final : public Thunk {
anatofuz
parents:
diff changeset
215 public:
anatofuz
parents:
diff changeset
216 MipsThunk(Symbol &dest) : Thunk(dest, 0) {}
anatofuz
parents:
diff changeset
217
anatofuz
parents:
diff changeset
218 uint32_t size() override { return 16; }
anatofuz
parents:
diff changeset
219 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
220 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
221 InputSection *getTargetInputSection() const override;
anatofuz
parents:
diff changeset
222 };
anatofuz
parents:
diff changeset
223
anatofuz
parents:
diff changeset
224 // microMIPS R2-R5 LA25 thunk
anatofuz
parents:
diff changeset
225 class MicroMipsThunk final : public Thunk {
anatofuz
parents:
diff changeset
226 public:
anatofuz
parents:
diff changeset
227 MicroMipsThunk(Symbol &dest) : Thunk(dest, 0) {}
anatofuz
parents:
diff changeset
228
anatofuz
parents:
diff changeset
229 uint32_t size() override { return 14; }
anatofuz
parents:
diff changeset
230 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
231 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
232 InputSection *getTargetInputSection() const override;
anatofuz
parents:
diff changeset
233 };
anatofuz
parents:
diff changeset
234
anatofuz
parents:
diff changeset
235 // microMIPS R6 LA25 thunk
anatofuz
parents:
diff changeset
236 class MicroMipsR6Thunk final : public Thunk {
anatofuz
parents:
diff changeset
237 public:
anatofuz
parents:
diff changeset
238 MicroMipsR6Thunk(Symbol &dest) : Thunk(dest, 0) {}
anatofuz
parents:
diff changeset
239
anatofuz
parents:
diff changeset
240 uint32_t size() override { return 12; }
anatofuz
parents:
diff changeset
241 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
242 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
243 InputSection *getTargetInputSection() const override;
anatofuz
parents:
diff changeset
244 };
anatofuz
parents:
diff changeset
245
anatofuz
parents:
diff changeset
246 class PPC32PltCallStub final : public Thunk {
anatofuz
parents:
diff changeset
247 public:
anatofuz
parents:
diff changeset
248 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
anatofuz
parents:
diff changeset
249 // decide the offsets in the call stub.
anatofuz
parents:
diff changeset
250 PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
anatofuz
parents:
diff changeset
251 Symbol &dest)
anatofuz
parents:
diff changeset
252 : Thunk(dest, rel.addend), file(isec.file) {}
anatofuz
parents:
diff changeset
253 uint32_t size() override { return 16; }
anatofuz
parents:
diff changeset
254 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
255 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
256 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
anatofuz
parents:
diff changeset
257
anatofuz
parents:
diff changeset
258 private:
anatofuz
parents:
diff changeset
259 // Records the call site of the call stub.
anatofuz
parents:
diff changeset
260 const InputFile *file;
anatofuz
parents:
diff changeset
261 };
anatofuz
parents:
diff changeset
262
anatofuz
parents:
diff changeset
263 class PPC32LongThunk final : public Thunk {
anatofuz
parents:
diff changeset
264 public:
anatofuz
parents:
diff changeset
265 PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
anatofuz
parents:
diff changeset
266 uint32_t size() override { return config->isPic ? 32 : 16; }
anatofuz
parents:
diff changeset
267 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
268 void addSymbols(ThunkSection &isec) override;
anatofuz
parents:
diff changeset
269 };
anatofuz
parents:
diff changeset
270
anatofuz
parents:
diff changeset
271 // PPC64 Plt call stubs.
anatofuz
parents:
diff changeset
272 // Any call site that needs to call through a plt entry needs a call stub in
anatofuz
parents:
diff changeset
273 // the .text section. The call stub is responsible for:
anatofuz
parents:
diff changeset
274 // 1) Saving the toc-pointer to the stack.
anatofuz
parents:
diff changeset
275 // 2) Loading the target functions address from the procedure linkage table into
anatofuz
parents:
diff changeset
276 // r12 for use by the target functions global entry point, and into the count
anatofuz
parents:
diff changeset
277 // register.
anatofuz
parents:
diff changeset
278 // 3) Transferring control to the target function through an indirect branch.
anatofuz
parents:
diff changeset
279 class PPC64PltCallStub final : public Thunk {
anatofuz
parents:
diff changeset
280 public:
anatofuz
parents:
diff changeset
281 PPC64PltCallStub(Symbol &dest) : Thunk(dest, 0) {}
anatofuz
parents:
diff changeset
282 uint32_t size() override { return 20; }
anatofuz
parents:
diff changeset
283 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
284 void addSymbols(ThunkSection &isec) override;
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
285 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
286 const Relocation &rel) const override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
287 };
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
288
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
289 // PPC64 R2 Save Stub
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
290 // When the caller requires a valid R2 TOC pointer but the callee does not
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
291 // require a TOC pointer and the callee cannot guarantee that it doesn't
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
292 // clobber R2 then we need to save R2. This stub:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
293 // 1) Saves the TOC pointer to the stack.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
294 // 2) Tail calls the callee.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
295 class PPC64R2SaveStub final : public Thunk {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
296 public:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
297 PPC64R2SaveStub(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
298 alignment = 16;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
299 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
300
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
301 // To prevent oscillations in layout when moving from short to long thunks
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
302 // we make sure that once a thunk has been set to long it cannot go back.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
303 bool getMayUseShortThunk() {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
304 if (!mayUseShortThunk)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
305 return false;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
306 if (!isInt<26>(computeOffset())) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
307 mayUseShortThunk = false;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
308 return false;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
309 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
310 return true;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
311 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
312 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
313 void writeTo(uint8_t *buf) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
314 void addSymbols(ThunkSection &isec) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
315 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
316 const Relocation &rel) const override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
317
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
318 private:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
319 // Transitioning from long to short can create layout oscillations in
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
320 // certain corner cases which would prevent the layout from converging.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
321 // This is similar to the handling for ARMThunk.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
322 bool mayUseShortThunk = true;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
323 int64_t computeOffset() const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
324 return destination.getVA() - (getThunkTargetSym()->getVA() + 4);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
325 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
326 };
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
327
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
328 // PPC64 R12 Setup Stub
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
329 // When a caller that does not maintain a toc-pointer performs a local call to
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
330 // a callee which requires a toc-pointer then we need this stub to place the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
331 // callee's global entry point into r12 without a save of R2.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
332 class PPC64R12SetupStub final : public Thunk {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
333 public:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
334 PPC64R12SetupStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
335 uint32_t size() override { return 32; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
336 void writeTo(uint8_t *buf) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
337 void addSymbols(ThunkSection &isec) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
338 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
339 const Relocation &rel) const override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
340 };
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
341
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
342 // PPC64 PC-relative PLT Stub
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
343 // When a caller that does not maintain a toc-pointer performs an extern call
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
344 // then this stub is needed for:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
345 // 1) Loading the target functions address from the procedure linkage table into
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
346 // r12 for use by the target functions global entry point, and into the count
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
347 // register with pc-relative instructions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
348 // 2) Transferring control to the target function through an indirect branch.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
349 class PPC64PCRelPLTStub final : public Thunk {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
350 public:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
351 PPC64PCRelPLTStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
352 uint32_t size() override { return 32; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
353 void writeTo(uint8_t *buf) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
354 void addSymbols(ThunkSection &isec) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
355 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
356 const Relocation &rel) const override;
150
anatofuz
parents:
diff changeset
357 };
anatofuz
parents:
diff changeset
358
anatofuz
parents:
diff changeset
359 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
anatofuz
parents:
diff changeset
360 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
361 // larger than that we need to emit a long-branch thunk. The target address
150
anatofuz
parents:
diff changeset
362 // of the callee is stored in a table to be accessed TOC-relative. Since the
anatofuz
parents:
diff changeset
363 // call must be local (a non-local call will have a PltCallStub instead) the
anatofuz
parents:
diff changeset
364 // table stores the address of the callee's local entry point. For
anatofuz
parents:
diff changeset
365 // position-independent code a corresponding relative dynamic relocation is
anatofuz
parents:
diff changeset
366 // used.
anatofuz
parents:
diff changeset
367 class PPC64LongBranchThunk : public Thunk {
anatofuz
parents:
diff changeset
368 public:
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
369 uint32_t size() override { return 32; }
150
anatofuz
parents:
diff changeset
370 void writeTo(uint8_t *buf) override;
anatofuz
parents:
diff changeset
371 void addSymbols(ThunkSection &isec) override;
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
372 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
373 const Relocation &rel) const override;
150
anatofuz
parents:
diff changeset
374
anatofuz
parents:
diff changeset
375 protected:
anatofuz
parents:
diff changeset
376 PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
anatofuz
parents:
diff changeset
377 };
anatofuz
parents:
diff changeset
378
anatofuz
parents:
diff changeset
379 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
anatofuz
parents:
diff changeset
380 public:
anatofuz
parents:
diff changeset
381 PPC64PILongBranchThunk(Symbol &dest, int64_t addend)
anatofuz
parents:
diff changeset
382 : PPC64LongBranchThunk(dest, addend) {
anatofuz
parents:
diff changeset
383 assert(!dest.isPreemptible);
anatofuz
parents:
diff changeset
384 if (Optional<uint32_t> index =
anatofuz
parents:
diff changeset
385 in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
anatofuz
parents:
diff changeset
386 mainPart->relaDyn->addReloc(
anatofuz
parents:
diff changeset
387 {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
anatofuz
parents:
diff changeset
388 true, &dest,
anatofuz
parents:
diff changeset
389 addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)});
anatofuz
parents:
diff changeset
390 }
anatofuz
parents:
diff changeset
391 }
anatofuz
parents:
diff changeset
392 };
anatofuz
parents:
diff changeset
393
anatofuz
parents:
diff changeset
394 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
anatofuz
parents:
diff changeset
395 public:
anatofuz
parents:
diff changeset
396 PPC64PDLongBranchThunk(Symbol &dest, int64_t addend)
anatofuz
parents:
diff changeset
397 : PPC64LongBranchThunk(dest, addend) {
anatofuz
parents:
diff changeset
398 in.ppc64LongBranchTarget->addEntry(&dest, addend);
anatofuz
parents:
diff changeset
399 }
anatofuz
parents:
diff changeset
400 };
anatofuz
parents:
diff changeset
401
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
402 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
403 // alignment. This gives a possible 26 bits of 'reach'. If the caller and
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
404 // callee do not use toc and the call offset is larger than 26 bits,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
405 // we need to emit a pc-rel based long-branch thunk. The target address of
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
406 // the callee is computed with a PC-relative offset.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
407 class PPC64PCRelLongBranchThunk final : public Thunk {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
408 public:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
409 PPC64PCRelLongBranchThunk(Symbol &dest, int64_t addend)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
410 : Thunk(dest, addend) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
411 alignment = 16;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
412 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
413 uint32_t size() override { return 32; }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
414 void writeTo(uint8_t *buf) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
415 void addSymbols(ThunkSection &isec) override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
416 bool isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
417 const Relocation &rel) const override;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
418 };
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
419
150
anatofuz
parents:
diff changeset
420 } // end anonymous namespace
anatofuz
parents:
diff changeset
421
anatofuz
parents:
diff changeset
422 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
anatofuz
parents:
diff changeset
423 InputSectionBase &section) {
anatofuz
parents:
diff changeset
424 Defined *d = addSyntheticLocal(name, type, value, /*size=*/0, section);
anatofuz
parents:
diff changeset
425 syms.push_back(d);
anatofuz
parents:
diff changeset
426 return d;
anatofuz
parents:
diff changeset
427 }
anatofuz
parents:
diff changeset
428
anatofuz
parents:
diff changeset
429 void Thunk::setOffset(uint64_t newOffset) {
anatofuz
parents:
diff changeset
430 for (Defined *d : syms)
anatofuz
parents:
diff changeset
431 d->value = d->value - offset + newOffset;
anatofuz
parents:
diff changeset
432 offset = newOffset;
anatofuz
parents:
diff changeset
433 }
anatofuz
parents:
diff changeset
434
anatofuz
parents:
diff changeset
435 // AArch64 long range Thunks
anatofuz
parents:
diff changeset
436
anatofuz
parents:
diff changeset
437 static uint64_t getAArch64ThunkDestVA(const Symbol &s, int64_t a) {
anatofuz
parents:
diff changeset
438 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(a);
anatofuz
parents:
diff changeset
439 return v;
anatofuz
parents:
diff changeset
440 }
anatofuz
parents:
diff changeset
441
anatofuz
parents:
diff changeset
442 void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
443 const uint8_t data[] = {
anatofuz
parents:
diff changeset
444 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
anatofuz
parents:
diff changeset
445 0x00, 0x02, 0x1f, 0xd6, // br x16
anatofuz
parents:
diff changeset
446 0x00, 0x00, 0x00, 0x00, // L0: .xword S
anatofuz
parents:
diff changeset
447 0x00, 0x00, 0x00, 0x00,
anatofuz
parents:
diff changeset
448 };
anatofuz
parents:
diff changeset
449 uint64_t s = getAArch64ThunkDestVA(destination, addend);
anatofuz
parents:
diff changeset
450 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
451 target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
anatofuz
parents:
diff changeset
452 }
anatofuz
parents:
diff changeset
453
anatofuz
parents:
diff changeset
454 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
455 addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
456 STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
457 addSymbol("$x", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
458 addSymbol("$d", STT_NOTYPE, 8, isec);
anatofuz
parents:
diff changeset
459 }
anatofuz
parents:
diff changeset
460
anatofuz
parents:
diff changeset
461 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
anatofuz
parents:
diff changeset
462 // using the small code model, including pc-relative ones. At time of writing
anatofuz
parents:
diff changeset
463 // clang and gcc do not support the large code model for position independent
anatofuz
parents:
diff changeset
464 // code so it is safe to use this for position independent thunks without
anatofuz
parents:
diff changeset
465 // worrying about the destination being more than 4Gb away.
anatofuz
parents:
diff changeset
466 void AArch64ADRPThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
467 const uint8_t data[] = {
anatofuz
parents:
diff changeset
468 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
anatofuz
parents:
diff changeset
469 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
anatofuz
parents:
diff changeset
470 0x00, 0x02, 0x1f, 0xd6, // br x16
anatofuz
parents:
diff changeset
471 };
anatofuz
parents:
diff changeset
472 uint64_t s = getAArch64ThunkDestVA(destination, addend);
anatofuz
parents:
diff changeset
473 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
474 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
475 target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
anatofuz
parents:
diff changeset
476 getAArch64Page(s) - getAArch64Page(p));
anatofuz
parents:
diff changeset
477 target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
anatofuz
parents:
diff changeset
478 }
anatofuz
parents:
diff changeset
479
anatofuz
parents:
diff changeset
480 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
481 addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
anatofuz
parents:
diff changeset
482 0, isec);
anatofuz
parents:
diff changeset
483 addSymbol("$x", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
484 }
anatofuz
parents:
diff changeset
485
anatofuz
parents:
diff changeset
486 // ARM Target Thunks
anatofuz
parents:
diff changeset
487 static uint64_t getARMThunkDestVA(const Symbol &s) {
anatofuz
parents:
diff changeset
488 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA();
anatofuz
parents:
diff changeset
489 return SignExtend64<32>(v);
anatofuz
parents:
diff changeset
490 }
anatofuz
parents:
diff changeset
491
anatofuz
parents:
diff changeset
492 // This function returns true if the target is not Thumb and is within 2^26, and
anatofuz
parents:
diff changeset
493 // it has not previously returned false (see comment for mayUseShortThunk).
anatofuz
parents:
diff changeset
494 bool ARMThunk::getMayUseShortThunk() {
anatofuz
parents:
diff changeset
495 if (!mayUseShortThunk)
anatofuz
parents:
diff changeset
496 return false;
anatofuz
parents:
diff changeset
497 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
498 if (s & 1) {
anatofuz
parents:
diff changeset
499 mayUseShortThunk = false;
anatofuz
parents:
diff changeset
500 return false;
anatofuz
parents:
diff changeset
501 }
anatofuz
parents:
diff changeset
502 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
503 int64_t offset = s - p - 8;
anatofuz
parents:
diff changeset
504 mayUseShortThunk = llvm::isInt<26>(offset);
anatofuz
parents:
diff changeset
505 return mayUseShortThunk;
anatofuz
parents:
diff changeset
506 }
anatofuz
parents:
diff changeset
507
anatofuz
parents:
diff changeset
508 void ARMThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
509 if (!getMayUseShortThunk()) {
anatofuz
parents:
diff changeset
510 writeLong(buf);
anatofuz
parents:
diff changeset
511 return;
anatofuz
parents:
diff changeset
512 }
anatofuz
parents:
diff changeset
513
anatofuz
parents:
diff changeset
514 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
515 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
516 int64_t offset = s - p - 8;
anatofuz
parents:
diff changeset
517 const uint8_t data[] = {
anatofuz
parents:
diff changeset
518 0x00, 0x00, 0x00, 0xea, // b S
anatofuz
parents:
diff changeset
519 };
anatofuz
parents:
diff changeset
520 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
521 target->relocateNoSym(buf, R_ARM_JUMP24, offset);
anatofuz
parents:
diff changeset
522 }
anatofuz
parents:
diff changeset
523
anatofuz
parents:
diff changeset
524 bool ARMThunk::isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
525 const Relocation &rel) const {
anatofuz
parents:
diff changeset
526 // Thumb branch relocations can't use BLX
anatofuz
parents:
diff changeset
527 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
anatofuz
parents:
diff changeset
528 }
anatofuz
parents:
diff changeset
529
anatofuz
parents:
diff changeset
530 // This function returns true if the target is Thumb and is within 2^25, and
anatofuz
parents:
diff changeset
531 // it has not previously returned false (see comment for mayUseShortThunk).
anatofuz
parents:
diff changeset
532 bool ThumbThunk::getMayUseShortThunk() {
anatofuz
parents:
diff changeset
533 if (!mayUseShortThunk)
anatofuz
parents:
diff changeset
534 return false;
anatofuz
parents:
diff changeset
535 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
536 if ((s & 1) == 0) {
anatofuz
parents:
diff changeset
537 mayUseShortThunk = false;
anatofuz
parents:
diff changeset
538 return false;
anatofuz
parents:
diff changeset
539 }
anatofuz
parents:
diff changeset
540 uint64_t p = getThunkTargetSym()->getVA() & ~1;
anatofuz
parents:
diff changeset
541 int64_t offset = s - p - 4;
anatofuz
parents:
diff changeset
542 mayUseShortThunk = llvm::isInt<25>(offset);
anatofuz
parents:
diff changeset
543 return mayUseShortThunk;
anatofuz
parents:
diff changeset
544 }
anatofuz
parents:
diff changeset
545
anatofuz
parents:
diff changeset
546 void ThumbThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
547 if (!getMayUseShortThunk()) {
anatofuz
parents:
diff changeset
548 writeLong(buf);
anatofuz
parents:
diff changeset
549 return;
anatofuz
parents:
diff changeset
550 }
anatofuz
parents:
diff changeset
551
anatofuz
parents:
diff changeset
552 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
553 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
554 int64_t offset = s - p - 4;
anatofuz
parents:
diff changeset
555 const uint8_t data[] = {
anatofuz
parents:
diff changeset
556 0x00, 0xf0, 0x00, 0xb0, // b.w S
anatofuz
parents:
diff changeset
557 };
anatofuz
parents:
diff changeset
558 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
559 target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
anatofuz
parents:
diff changeset
560 }
anatofuz
parents:
diff changeset
561
anatofuz
parents:
diff changeset
562 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
563 const Relocation &rel) const {
anatofuz
parents:
diff changeset
564 // ARM branch relocations can't use BLX
anatofuz
parents:
diff changeset
565 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
anatofuz
parents:
diff changeset
566 }
anatofuz
parents:
diff changeset
567
anatofuz
parents:
diff changeset
568 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
569 const uint8_t data[] = {
anatofuz
parents:
diff changeset
570 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
anatofuz
parents:
diff changeset
571 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
anatofuz
parents:
diff changeset
572 0x1c, 0xff, 0x2f, 0xe1, // bx ip
anatofuz
parents:
diff changeset
573 };
anatofuz
parents:
diff changeset
574 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
575 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
576 target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
anatofuz
parents:
diff changeset
577 target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
anatofuz
parents:
diff changeset
578 }
anatofuz
parents:
diff changeset
579
anatofuz
parents:
diff changeset
580 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
581 addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
582 STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
583 addSymbol("$a", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
584 }
anatofuz
parents:
diff changeset
585
anatofuz
parents:
diff changeset
586 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
587 const uint8_t data[] = {
anatofuz
parents:
diff changeset
588 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
anatofuz
parents:
diff changeset
589 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
anatofuz
parents:
diff changeset
590 0x60, 0x47, // bx ip
anatofuz
parents:
diff changeset
591 };
anatofuz
parents:
diff changeset
592 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
593 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
594 target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
anatofuz
parents:
diff changeset
595 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
anatofuz
parents:
diff changeset
596 }
anatofuz
parents:
diff changeset
597
anatofuz
parents:
diff changeset
598 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
599 addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
600 STT_FUNC, 1, isec);
anatofuz
parents:
diff changeset
601 addSymbol("$t", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
602 }
anatofuz
parents:
diff changeset
603
anatofuz
parents:
diff changeset
604 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
605 const uint8_t data[] = {
anatofuz
parents:
diff changeset
606 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
anatofuz
parents:
diff changeset
607 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
anatofuz
parents:
diff changeset
608 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
anatofuz
parents:
diff changeset
609 0x1c, 0xff, 0x2f, 0xe1, // bx ip
anatofuz
parents:
diff changeset
610 };
anatofuz
parents:
diff changeset
611 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
612 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
613 int64_t offset = s - p - 16;
anatofuz
parents:
diff changeset
614 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
615 target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
anatofuz
parents:
diff changeset
616 target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
anatofuz
parents:
diff changeset
617 }
anatofuz
parents:
diff changeset
618
anatofuz
parents:
diff changeset
619 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
620 addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
anatofuz
parents:
diff changeset
621 0, isec);
anatofuz
parents:
diff changeset
622 addSymbol("$a", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
623 }
anatofuz
parents:
diff changeset
624
anatofuz
parents:
diff changeset
625 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
626 const uint8_t data[] = {
anatofuz
parents:
diff changeset
627 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
anatofuz
parents:
diff changeset
628 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
anatofuz
parents:
diff changeset
629 0xfc, 0x44, // L1: add ip, pc
anatofuz
parents:
diff changeset
630 0x60, 0x47, // bx ip
anatofuz
parents:
diff changeset
631 };
anatofuz
parents:
diff changeset
632 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
633 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
anatofuz
parents:
diff changeset
634 int64_t offset = s - p - 12;
anatofuz
parents:
diff changeset
635 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
636 target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
anatofuz
parents:
diff changeset
637 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
anatofuz
parents:
diff changeset
638 }
anatofuz
parents:
diff changeset
639
anatofuz
parents:
diff changeset
640 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
641 addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
642 STT_FUNC, 1, isec);
anatofuz
parents:
diff changeset
643 addSymbol("$t", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
644 }
anatofuz
parents:
diff changeset
645
anatofuz
parents:
diff changeset
646 void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
647 const uint8_t data[] = {
anatofuz
parents:
diff changeset
648 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
anatofuz
parents:
diff changeset
649 0x00, 0x00, 0x00, 0x00, // L1: .word S
anatofuz
parents:
diff changeset
650 };
anatofuz
parents:
diff changeset
651 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
652 target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
anatofuz
parents:
diff changeset
653 }
anatofuz
parents:
diff changeset
654
anatofuz
parents:
diff changeset
655 void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
656 addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
657 STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
658 addSymbol("$a", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
659 addSymbol("$d", STT_NOTYPE, 4, isec);
anatofuz
parents:
diff changeset
660 }
anatofuz
parents:
diff changeset
661
anatofuz
parents:
diff changeset
662 bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
663 const Relocation &rel) const {
anatofuz
parents:
diff changeset
664 // Thumb branch relocations can't use BLX
anatofuz
parents:
diff changeset
665 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
anatofuz
parents:
diff changeset
666 }
anatofuz
parents:
diff changeset
667
anatofuz
parents:
diff changeset
668 void ARMV5PILongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
669 const uint8_t data[] = {
anatofuz
parents:
diff changeset
670 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
anatofuz
parents:
diff changeset
671 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
anatofuz
parents:
diff changeset
672 0x1c, 0xff, 0x2f, 0xe1, // bx ip
anatofuz
parents:
diff changeset
673 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
anatofuz
parents:
diff changeset
674 };
anatofuz
parents:
diff changeset
675 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
676 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
anatofuz
parents:
diff changeset
677 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
678 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
anatofuz
parents:
diff changeset
679 }
anatofuz
parents:
diff changeset
680
anatofuz
parents:
diff changeset
681 void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
682 addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
anatofuz
parents:
diff changeset
683 0, isec);
anatofuz
parents:
diff changeset
684 addSymbol("$a", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
685 addSymbol("$d", STT_NOTYPE, 12, isec);
anatofuz
parents:
diff changeset
686 }
anatofuz
parents:
diff changeset
687
anatofuz
parents:
diff changeset
688 bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
689 const Relocation &rel) const {
anatofuz
parents:
diff changeset
690 // Thumb branch relocations can't use BLX
anatofuz
parents:
diff changeset
691 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
anatofuz
parents:
diff changeset
692 }
anatofuz
parents:
diff changeset
693
anatofuz
parents:
diff changeset
694 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
695 // Most Thumb instructions cannot access the high registers r8 - r15. As the
anatofuz
parents:
diff changeset
696 // only register we can corrupt is r12 we must instead spill a low register
anatofuz
parents:
diff changeset
697 // to the stack to use as a scratch register. We push r1 even though we
anatofuz
parents:
diff changeset
698 // don't need to get some space to use for the return address.
anatofuz
parents:
diff changeset
699 const uint8_t data[] = {
anatofuz
parents:
diff changeset
700 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
anatofuz
parents:
diff changeset
701 0x01, 0x48, // ldr r0, [pc, #4] ; L1
anatofuz
parents:
diff changeset
702 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
anatofuz
parents:
diff changeset
703 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
anatofuz
parents:
diff changeset
704 0x00, 0x00, 0x00, 0x00 // L1: .word S
anatofuz
parents:
diff changeset
705 };
anatofuz
parents:
diff changeset
706 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
707 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
708 target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
anatofuz
parents:
diff changeset
709 }
anatofuz
parents:
diff changeset
710
anatofuz
parents:
diff changeset
711 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
712 addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
713 STT_FUNC, 1, isec);
anatofuz
parents:
diff changeset
714 addSymbol("$t", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
715 addSymbol("$d", STT_NOTYPE, 8, isec);
anatofuz
parents:
diff changeset
716 }
anatofuz
parents:
diff changeset
717
anatofuz
parents:
diff changeset
718 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
anatofuz
parents:
diff changeset
719 // Most Thumb instructions cannot access the high registers r8 - r15. As the
anatofuz
parents:
diff changeset
720 // only register we can corrupt is ip (r12) we must instead spill a low
anatofuz
parents:
diff changeset
721 // register to the stack to use as a scratch register.
anatofuz
parents:
diff changeset
722 const uint8_t data[] = {
anatofuz
parents:
diff changeset
723 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
anatofuz
parents:
diff changeset
724 0x02, 0x48, // ldr r0, [pc, #8] ; L2
anatofuz
parents:
diff changeset
725 0x84, 0x46, // mov ip, r0 ; high to low register
anatofuz
parents:
diff changeset
726 0x01, 0xbc, // pop {r0} ; restore scratch register
anatofuz
parents:
diff changeset
727 0xe7, 0x44, // L1: add pc, ip ; transfer control
anatofuz
parents:
diff changeset
728 0xc0, 0x46, // nop ; pad to 4-byte boundary
anatofuz
parents:
diff changeset
729 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
anatofuz
parents:
diff changeset
730 };
anatofuz
parents:
diff changeset
731 uint64_t s = getARMThunkDestVA(destination);
anatofuz
parents:
diff changeset
732 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
anatofuz
parents:
diff changeset
733 memcpy(buf, data, sizeof(data));
anatofuz
parents:
diff changeset
734 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
anatofuz
parents:
diff changeset
735 }
anatofuz
parents:
diff changeset
736
anatofuz
parents:
diff changeset
737 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
738 addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
anatofuz
parents:
diff changeset
739 STT_FUNC, 1, isec);
anatofuz
parents:
diff changeset
740 addSymbol("$t", STT_NOTYPE, 0, isec);
anatofuz
parents:
diff changeset
741 addSymbol("$d", STT_NOTYPE, 12, isec);
anatofuz
parents:
diff changeset
742 }
anatofuz
parents:
diff changeset
743
anatofuz
parents:
diff changeset
744 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
anatofuz
parents:
diff changeset
745 void MipsThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
746 uint64_t s = destination.getVA();
anatofuz
parents:
diff changeset
747 write32(buf, 0x3c190000); // lui $25, %hi(func)
anatofuz
parents:
diff changeset
748 write32(buf + 4, 0x08000000 | (s >> 2)); // j func
anatofuz
parents:
diff changeset
749 write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
anatofuz
parents:
diff changeset
750 write32(buf + 12, 0x00000000); // nop
anatofuz
parents:
diff changeset
751 target->relocateNoSym(buf, R_MIPS_HI16, s);
anatofuz
parents:
diff changeset
752 target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
anatofuz
parents:
diff changeset
753 }
anatofuz
parents:
diff changeset
754
anatofuz
parents:
diff changeset
755 void MipsThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
756 addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
anatofuz
parents:
diff changeset
757 isec);
anatofuz
parents:
diff changeset
758 }
anatofuz
parents:
diff changeset
759
anatofuz
parents:
diff changeset
760 InputSection *MipsThunk::getTargetInputSection() const {
anatofuz
parents:
diff changeset
761 auto &dr = cast<Defined>(destination);
anatofuz
parents:
diff changeset
762 return dyn_cast<InputSection>(dr.section);
anatofuz
parents:
diff changeset
763 }
anatofuz
parents:
diff changeset
764
anatofuz
parents:
diff changeset
765 // Write microMIPS R2-R5 LA25 thunk code
anatofuz
parents:
diff changeset
766 // to call PIC function from the non-PIC one.
anatofuz
parents:
diff changeset
767 void MicroMipsThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
768 uint64_t s = destination.getVA();
anatofuz
parents:
diff changeset
769 write16(buf, 0x41b9); // lui $25, %hi(func)
anatofuz
parents:
diff changeset
770 write16(buf + 4, 0xd400); // j func
anatofuz
parents:
diff changeset
771 write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func)
anatofuz
parents:
diff changeset
772 write16(buf + 12, 0x0c00); // nop
anatofuz
parents:
diff changeset
773 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
anatofuz
parents:
diff changeset
774 target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
anatofuz
parents:
diff changeset
775 target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
anatofuz
parents:
diff changeset
776 }
anatofuz
parents:
diff changeset
777
anatofuz
parents:
diff changeset
778 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
779 Defined *d = addSymbol(
anatofuz
parents:
diff changeset
780 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
781 d->stOther |= STO_MIPS_MICROMIPS;
anatofuz
parents:
diff changeset
782 }
anatofuz
parents:
diff changeset
783
anatofuz
parents:
diff changeset
784 InputSection *MicroMipsThunk::getTargetInputSection() const {
anatofuz
parents:
diff changeset
785 auto &dr = cast<Defined>(destination);
anatofuz
parents:
diff changeset
786 return dyn_cast<InputSection>(dr.section);
anatofuz
parents:
diff changeset
787 }
anatofuz
parents:
diff changeset
788
anatofuz
parents:
diff changeset
789 // Write microMIPS R6 LA25 thunk code
anatofuz
parents:
diff changeset
790 // to call PIC function from the non-PIC one.
anatofuz
parents:
diff changeset
791 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
792 uint64_t s = destination.getVA();
anatofuz
parents:
diff changeset
793 uint64_t p = getThunkTargetSym()->getVA();
anatofuz
parents:
diff changeset
794 write16(buf, 0x1320); // lui $25, %hi(func)
anatofuz
parents:
diff changeset
795 write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func)
anatofuz
parents:
diff changeset
796 write16(buf + 8, 0x9400); // bc func
anatofuz
parents:
diff changeset
797 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
anatofuz
parents:
diff changeset
798 target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
anatofuz
parents:
diff changeset
799 target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
anatofuz
parents:
diff changeset
800 }
anatofuz
parents:
diff changeset
801
anatofuz
parents:
diff changeset
802 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
803 Defined *d = addSymbol(
anatofuz
parents:
diff changeset
804 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
805 d->stOther |= STO_MIPS_MICROMIPS;
anatofuz
parents:
diff changeset
806 }
anatofuz
parents:
diff changeset
807
anatofuz
parents:
diff changeset
808 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
anatofuz
parents:
diff changeset
809 auto &dr = cast<Defined>(destination);
anatofuz
parents:
diff changeset
810 return dyn_cast<InputSection>(dr.section);
anatofuz
parents:
diff changeset
811 }
anatofuz
parents:
diff changeset
812
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
813 void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
814 const InputFile *file, int64_t addend) {
150
anatofuz
parents:
diff changeset
815 if (!config->isPic) {
anatofuz
parents:
diff changeset
816 write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
anatofuz
parents:
diff changeset
817 write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
anatofuz
parents:
diff changeset
818 write32(buf + 8, 0x7d6903a6); // mtctr r11
anatofuz
parents:
diff changeset
819 write32(buf + 12, 0x4e800420); // bctr
anatofuz
parents:
diff changeset
820 return;
anatofuz
parents:
diff changeset
821 }
anatofuz
parents:
diff changeset
822 uint32_t offset;
anatofuz
parents:
diff changeset
823 if (addend >= 0x8000) {
anatofuz
parents:
diff changeset
824 // The stub loads an address relative to r30 (.got2+Addend). Addend is
anatofuz
parents:
diff changeset
825 // almost always 0x8000. The address of .got2 is different in another object
anatofuz
parents:
diff changeset
826 // file, so a stub cannot be shared.
anatofuz
parents:
diff changeset
827 offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
anatofuz
parents:
diff changeset
828 file->ppc32Got2OutSecOff + addend);
anatofuz
parents:
diff changeset
829 } else {
anatofuz
parents:
diff changeset
830 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
anatofuz
parents:
diff changeset
831 // currently the address of .got).
anatofuz
parents:
diff changeset
832 offset = gotPltVA - in.got->getVA();
anatofuz
parents:
diff changeset
833 }
anatofuz
parents:
diff changeset
834 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
anatofuz
parents:
diff changeset
835 if (ha == 0) {
anatofuz
parents:
diff changeset
836 write32(buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
anatofuz
parents:
diff changeset
837 write32(buf + 4, 0x7d6903a6); // mtctr r11
anatofuz
parents:
diff changeset
838 write32(buf + 8, 0x4e800420); // bctr
anatofuz
parents:
diff changeset
839 write32(buf + 12, 0x60000000); // nop
anatofuz
parents:
diff changeset
840 } else {
anatofuz
parents:
diff changeset
841 write32(buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
anatofuz
parents:
diff changeset
842 write32(buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
anatofuz
parents:
diff changeset
843 write32(buf + 8, 0x7d6903a6); // mtctr r11
anatofuz
parents:
diff changeset
844 write32(buf + 12, 0x4e800420); // bctr
anatofuz
parents:
diff changeset
845 }
anatofuz
parents:
diff changeset
846 }
anatofuz
parents:
diff changeset
847
anatofuz
parents:
diff changeset
848 void PPC32PltCallStub::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
849 writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend);
anatofuz
parents:
diff changeset
850 }
anatofuz
parents:
diff changeset
851
anatofuz
parents:
diff changeset
852 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
853 std::string buf;
anatofuz
parents:
diff changeset
854 raw_string_ostream os(buf);
anatofuz
parents:
diff changeset
855 os << format_hex_no_prefix(addend, 8);
anatofuz
parents:
diff changeset
856 if (!config->isPic)
anatofuz
parents:
diff changeset
857 os << ".plt_call32.";
anatofuz
parents:
diff changeset
858 else if (addend >= 0x8000)
anatofuz
parents:
diff changeset
859 os << ".got2.plt_pic32.";
anatofuz
parents:
diff changeset
860 else
anatofuz
parents:
diff changeset
861 os << ".plt_pic32.";
anatofuz
parents:
diff changeset
862 os << destination.getName();
anatofuz
parents:
diff changeset
863 addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
anatofuz
parents:
diff changeset
864 }
anatofuz
parents:
diff changeset
865
anatofuz
parents:
diff changeset
866 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
anatofuz
parents:
diff changeset
867 const Relocation &rel) const {
anatofuz
parents:
diff changeset
868 return !config->isPic || (isec.file == file && rel.addend == addend);
anatofuz
parents:
diff changeset
869 }
anatofuz
parents:
diff changeset
870
anatofuz
parents:
diff changeset
871 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
872 addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
anatofuz
parents:
diff changeset
873 isec);
anatofuz
parents:
diff changeset
874 }
anatofuz
parents:
diff changeset
875
anatofuz
parents:
diff changeset
876 void PPC32LongThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
877 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
anatofuz
parents:
diff changeset
878 auto lo = [](uint32_t v) -> uint16_t { return v; };
anatofuz
parents:
diff changeset
879 uint32_t d = destination.getVA(addend);
anatofuz
parents:
diff changeset
880 if (config->isPic) {
anatofuz
parents:
diff changeset
881 uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
anatofuz
parents:
diff changeset
882 write32(buf + 0, 0x7c0802a6); // mflr r12,0
anatofuz
parents:
diff changeset
883 write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
anatofuz
parents:
diff changeset
884 write32(buf + 8, 0x7d8802a6); // mtctr r12
anatofuz
parents:
diff changeset
885 write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
anatofuz
parents:
diff changeset
886 write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
anatofuz
parents:
diff changeset
887 write32(buf + 20, 0x7c0803a6); // mtlr r0
anatofuz
parents:
diff changeset
888 buf += 24;
anatofuz
parents:
diff changeset
889 } else {
anatofuz
parents:
diff changeset
890 write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
anatofuz
parents:
diff changeset
891 write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
anatofuz
parents:
diff changeset
892 buf += 8;
anatofuz
parents:
diff changeset
893 }
anatofuz
parents:
diff changeset
894 write32(buf + 0, 0x7d8903a6); // mtctr r12
anatofuz
parents:
diff changeset
895 write32(buf + 4, 0x4e800420); // bctr
anatofuz
parents:
diff changeset
896 }
anatofuz
parents:
diff changeset
897
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
898 void elf::writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
150
anatofuz
parents:
diff changeset
899 uint16_t offHa = (offset + 0x8000) >> 16;
anatofuz
parents:
diff changeset
900 uint16_t offLo = offset & 0xffff;
anatofuz
parents:
diff changeset
901
anatofuz
parents:
diff changeset
902 write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
anatofuz
parents:
diff changeset
903 write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
anatofuz
parents:
diff changeset
904 write32(buf + 8, 0x7d8903a6); // mtctr r12
anatofuz
parents:
diff changeset
905 write32(buf + 12, 0x4e800420); // bctr
anatofuz
parents:
diff changeset
906 }
anatofuz
parents:
diff changeset
907
anatofuz
parents:
diff changeset
908 void PPC64PltCallStub::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
909 int64_t offset = destination.getGotPltVA() - getPPC64TocBase();
anatofuz
parents:
diff changeset
910 // Save the TOC pointer to the save-slot reserved in the call frame.
anatofuz
parents:
diff changeset
911 write32(buf + 0, 0xf8410018); // std r2,24(r1)
anatofuz
parents:
diff changeset
912 writePPC64LoadAndBranch(buf + 4, offset);
anatofuz
parents:
diff changeset
913 }
anatofuz
parents:
diff changeset
914
anatofuz
parents:
diff changeset
915 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
916 Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
anatofuz
parents:
diff changeset
917 0, isec);
anatofuz
parents:
diff changeset
918 s->needsTocRestore = true;
anatofuz
parents:
diff changeset
919 s->file = destination.file;
anatofuz
parents:
diff changeset
920 }
anatofuz
parents:
diff changeset
921
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
922 bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
923 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
924 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
925 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
926
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
927 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
928 const int64_t offset = computeOffset();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
929 write32(buf + 0, 0xf8410018); // std r2,24(r1)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
930 // The branch offset needs to fit in 26 bits.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
931 if (getMayUseShortThunk()) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
932 write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
933 } else if (isInt<34>(offset)) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
934 int nextInstOffset;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
935 if (!config->Power10Stub) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
936 uint64_t tocOffset = destination.getVA() - getPPC64TocBase();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
937 if (tocOffset >> 16 > 0) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
938 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
939 const uint64_t addis = ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
940 write32(buf + 4, addis); // addis r12, r2 , top of offset
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
941 write32(buf + 8, addi); // addi r12, r12, bottom of offset
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
942 nextInstOffset = 12;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
943 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
944 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
945 write32(buf + 4, addi); // addi r12, r2, offset
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
946 nextInstOffset = 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
947 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
948 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
949 const uint64_t paddi = PADDI_R12_NO_DISP |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
950 (((offset >> 16) & 0x3ffff) << 32) |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
951 (offset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
952 writePrefixedInstruction(buf + 4, paddi); // paddi r12, 0, func@pcrel, 1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
953 nextInstOffset = 12;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
954 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
955 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
956 write32(buf + nextInstOffset + 4, BCTR); // bctr
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
957 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
958 in.ppc64LongBranchTarget->addEntry(&destination, addend);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
959 const int64_t offsetFromTOC =
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
960 in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
961 getPPC64TocBase();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
962 writePPC64LoadAndBranch(buf + 4, offsetFromTOC);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
963 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
964 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
965
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
966 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
967 Defined *s = addSymbol(saver.save("__toc_save_" + destination.getName()),
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
968 STT_FUNC, 0, isec);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
969 s->needsTocRestore = true;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
970 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
971
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
972 bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
973 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
974 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
975 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
976
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
977 void PPC64R12SetupStub::writeTo(uint8_t *buf) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
978 int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
979 if (!isInt<34>(offset))
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
980 reportRangeError(buf, offset, 34, destination, "R12 setup stub offset");
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
981
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
982 int nextInstOffset;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
983 if (!config->Power10Stub) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
984 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
985 write32(buf + 0, 0x7c0802a6); // mflr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
986 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
987 write32(buf + 8, 0x7d6802a6); // mflr r11
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
988 write32(buf + 12, 0x7d8803a6); // mtlr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
989 write32(buf + 16, 0x3d8b0000 | computeHiBits(off));// addis r12,r11,off@ha
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
990 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
991 nextInstOffset = 24;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
992 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
993 uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
994 (offset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
995 writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
996 nextInstOffset = 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
997 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
998 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
999 write32(buf + nextInstOffset + 4, BCTR); // bctr
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1000 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1001
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1002 void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1003 addSymbol(saver.save("__gep_setup_" + destination.getName()), STT_FUNC, 0,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1004 isec);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1005 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1006
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1007 bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1008 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1009 return rel.type == R_PPC64_REL24_NOTOC;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1010 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1011
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1012 void PPC64PCRelPLTStub::writeTo(uint8_t *buf) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1013 int nextInstOffset = 0;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1014 int64_t offset = destination.getGotPltVA() - getThunkTargetSym()->getVA();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1015
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1016 if (config->Power10Stub) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1017 if (!isInt<34>(offset))
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1018 reportRangeError(buf, offset, 34, destination,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1019 "PC-relative PLT stub offset");
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1020 const uint64_t pld = PLD_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1021 (offset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1022 writePrefixedInstruction(buf + 0, pld); // pld r12, func@plt@pcrel
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1023 nextInstOffset = 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1024 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1025 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1026 write32(buf + 0, 0x7c0802a6); // mflr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1027 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1028 write32(buf + 8, 0x7d6802a6); // mflr r11
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1029 write32(buf + 12, 0x7d8803a6); // mtlr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1030 write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1031 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1032 nextInstOffset = 24;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1033 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1034 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1035 write32(buf + nextInstOffset + 4, BCTR); // bctr
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1036 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1037
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1038 void PPC64PCRelPLTStub::addSymbols(ThunkSection &isec) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1039 addSymbol(saver.save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1040 isec);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1041 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1042
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1043 bool PPC64PCRelPLTStub::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1044 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1045 return rel.type == R_PPC64_REL24_NOTOC;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1046 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1047
150
anatofuz
parents:
diff changeset
1048 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
anatofuz
parents:
diff changeset
1049 int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
anatofuz
parents:
diff changeset
1050 getPPC64TocBase();
anatofuz
parents:
diff changeset
1051 writePPC64LoadAndBranch(buf, offset);
anatofuz
parents:
diff changeset
1052 }
anatofuz
parents:
diff changeset
1053
anatofuz
parents:
diff changeset
1054 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
anatofuz
parents:
diff changeset
1055 addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
anatofuz
parents:
diff changeset
1056 isec);
anatofuz
parents:
diff changeset
1057 }
anatofuz
parents:
diff changeset
1058
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1059 bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1060 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1061 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1062 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1063
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1064 void PPC64PCRelLongBranchThunk::writeTo(uint8_t *buf) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1065 int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1066 if (!isInt<34>(offset))
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1067 reportRangeError(buf, offset, 34, destination,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1068 "PC-relative long branch stub offset");
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1069
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1070 int nextInstOffset;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1071 if (!config->Power10Stub) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1072 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1073 write32(buf + 0, 0x7c0802a6); // mflr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1074 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1075 write32(buf + 8, 0x7d6802a6); // mflr r11
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1076 write32(buf + 12, 0x7d8803a6); // mtlr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1077 write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1078 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1079 nextInstOffset = 24;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1080 } else {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1081 uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1082 (offset & 0xffff);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1083 writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1084 nextInstOffset = 8;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1085 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1086 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1087 write32(buf + nextInstOffset + 4, BCTR); // bctr
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1088 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1089
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1090 void PPC64PCRelLongBranchThunk::addSymbols(ThunkSection &isec) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1091 addSymbol(saver.save("__long_branch_pcrel_" + destination.getName()),
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1092 STT_FUNC, 0, isec);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1093 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1094
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1095 bool PPC64PCRelLongBranchThunk::isCompatibleWith(const InputSection &isec,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1096 const Relocation &rel) const {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1097 return rel.type == R_PPC64_REL24_NOTOC;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1098 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1099
150
anatofuz
parents:
diff changeset
1100 Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {}
anatofuz
parents:
diff changeset
1101
anatofuz
parents:
diff changeset
1102 Thunk::~Thunk() = default;
anatofuz
parents:
diff changeset
1103
anatofuz
parents:
diff changeset
1104 static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1105 if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1106 type != R_AARCH64_PLT32)
150
anatofuz
parents:
diff changeset
1107 fatal("unrecognized relocation type");
anatofuz
parents:
diff changeset
1108 if (config->picThunk)
anatofuz
parents:
diff changeset
1109 return make<AArch64ADRPThunk>(s, a);
anatofuz
parents:
diff changeset
1110 return make<AArch64ABSLongThunk>(s, a);
anatofuz
parents:
diff changeset
1111 }
anatofuz
parents:
diff changeset
1112
anatofuz
parents:
diff changeset
1113 // Creates a thunk for Thumb-ARM interworking.
anatofuz
parents:
diff changeset
1114 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means
anatofuz
parents:
diff changeset
1115 // - MOVT and MOVW instructions cannot be used
anatofuz
parents:
diff changeset
1116 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
anatofuz
parents:
diff changeset
1117 // be transformed into a BLX
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1118 static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s, int64_t a) {
150
anatofuz
parents:
diff changeset
1119 switch (reloc) {
anatofuz
parents:
diff changeset
1120 case R_ARM_PC24:
anatofuz
parents:
diff changeset
1121 case R_ARM_PLT32:
anatofuz
parents:
diff changeset
1122 case R_ARM_JUMP24:
anatofuz
parents:
diff changeset
1123 case R_ARM_CALL:
anatofuz
parents:
diff changeset
1124 case R_ARM_THM_CALL:
anatofuz
parents:
diff changeset
1125 if (config->picThunk)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1126 return make<ARMV5PILongThunk>(s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1127 return make<ARMV5ABSLongThunk>(s, a);
150
anatofuz
parents:
diff changeset
1128 }
anatofuz
parents:
diff changeset
1129 fatal("relocation " + toString(reloc) + " to " + toString(s) +
anatofuz
parents:
diff changeset
1130 " not supported for Armv5 or Armv6 targets");
anatofuz
parents:
diff changeset
1131 }
anatofuz
parents:
diff changeset
1132
anatofuz
parents:
diff changeset
1133 // Create a thunk for Thumb long branch on V6-M.
anatofuz
parents:
diff changeset
1134 // Arm Architecture v6-M only supports Thumb instructions. This means
anatofuz
parents:
diff changeset
1135 // - MOVT and MOVW instructions cannot be used.
anatofuz
parents:
diff changeset
1136 // - Only a limited number of instructions can access registers r8 and above
anatofuz
parents:
diff changeset
1137 // - No interworking support is needed (all Thumb).
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1138 static Thunk *addThunkV6M(RelType reloc, Symbol &s, int64_t a) {
150
anatofuz
parents:
diff changeset
1139 switch (reloc) {
anatofuz
parents:
diff changeset
1140 case R_ARM_THM_JUMP19:
anatofuz
parents:
diff changeset
1141 case R_ARM_THM_JUMP24:
anatofuz
parents:
diff changeset
1142 case R_ARM_THM_CALL:
anatofuz
parents:
diff changeset
1143 if (config->isPic)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1144 return make<ThumbV6MPILongThunk>(s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1145 return make<ThumbV6MABSLongThunk>(s, a);
150
anatofuz
parents:
diff changeset
1146 }
anatofuz
parents:
diff changeset
1147 fatal("relocation " + toString(reloc) + " to " + toString(s) +
anatofuz
parents:
diff changeset
1148 " not supported for Armv6-M targets");
anatofuz
parents:
diff changeset
1149 }
anatofuz
parents:
diff changeset
1150
anatofuz
parents:
diff changeset
1151 // Creates a thunk for Thumb-ARM interworking or branch range extension.
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1152 static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
150
anatofuz
parents:
diff changeset
1153 // Decide which Thunk is needed based on:
anatofuz
parents:
diff changeset
1154 // Available instruction set
anatofuz
parents:
diff changeset
1155 // - An Arm Thunk can only be used if Arm state is available.
anatofuz
parents:
diff changeset
1156 // - A Thumb Thunk can only be used if Thumb state is available.
anatofuz
parents:
diff changeset
1157 // - Can only use a Thunk if it uses instructions that the Target supports.
anatofuz
parents:
diff changeset
1158 // Relocation is branch or branch and link
anatofuz
parents:
diff changeset
1159 // - Branch instructions cannot change state, can only select Thunk that
anatofuz
parents:
diff changeset
1160 // starts in the same state as the caller.
anatofuz
parents:
diff changeset
1161 // - Branch and link relocations can change state, can select Thunks from
anatofuz
parents:
diff changeset
1162 // either Arm or Thumb.
anatofuz
parents:
diff changeset
1163 // Position independent Thunks if we require position independent code.
anatofuz
parents:
diff changeset
1164
anatofuz
parents:
diff changeset
1165 // Handle architectures that have restrictions on the instructions that they
anatofuz
parents:
diff changeset
1166 // can use in Thunks. The flags below are set by reading the BuildAttributes
anatofuz
parents:
diff changeset
1167 // of the input objects. InputFiles.cpp contains the mapping from ARM
anatofuz
parents:
diff changeset
1168 // architecture to flag.
anatofuz
parents:
diff changeset
1169 if (!config->armHasMovtMovw) {
anatofuz
parents:
diff changeset
1170 if (!config->armJ1J2BranchEncoding)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1171 return addThunkPreArmv7(reloc, s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1172 return addThunkV6M(reloc, s, a);
150
anatofuz
parents:
diff changeset
1173 }
anatofuz
parents:
diff changeset
1174
anatofuz
parents:
diff changeset
1175 switch (reloc) {
anatofuz
parents:
diff changeset
1176 case R_ARM_PC24:
anatofuz
parents:
diff changeset
1177 case R_ARM_PLT32:
anatofuz
parents:
diff changeset
1178 case R_ARM_JUMP24:
anatofuz
parents:
diff changeset
1179 case R_ARM_CALL:
anatofuz
parents:
diff changeset
1180 if (config->picThunk)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1181 return make<ARMV7PILongThunk>(s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1182 return make<ARMV7ABSLongThunk>(s, a);
150
anatofuz
parents:
diff changeset
1183 case R_ARM_THM_JUMP19:
anatofuz
parents:
diff changeset
1184 case R_ARM_THM_JUMP24:
anatofuz
parents:
diff changeset
1185 case R_ARM_THM_CALL:
anatofuz
parents:
diff changeset
1186 if (config->picThunk)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1187 return make<ThumbV7PILongThunk>(s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1188 return make<ThumbV7ABSLongThunk>(s, a);
150
anatofuz
parents:
diff changeset
1189 }
anatofuz
parents:
diff changeset
1190 fatal("unrecognized relocation type");
anatofuz
parents:
diff changeset
1191 }
anatofuz
parents:
diff changeset
1192
anatofuz
parents:
diff changeset
1193 static Thunk *addThunkMips(RelType type, Symbol &s) {
anatofuz
parents:
diff changeset
1194 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6())
anatofuz
parents:
diff changeset
1195 return make<MicroMipsR6Thunk>(s);
anatofuz
parents:
diff changeset
1196 if (s.stOther & STO_MIPS_MICROMIPS)
anatofuz
parents:
diff changeset
1197 return make<MicroMipsThunk>(s);
anatofuz
parents:
diff changeset
1198 return make<MipsThunk>(s);
anatofuz
parents:
diff changeset
1199 }
anatofuz
parents:
diff changeset
1200
anatofuz
parents:
diff changeset
1201 static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
anatofuz
parents:
diff changeset
1202 Symbol &s) {
anatofuz
parents:
diff changeset
1203 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
anatofuz
parents:
diff changeset
1204 rel.type == R_PPC_PLTREL24) &&
anatofuz
parents:
diff changeset
1205 "unexpected relocation type for thunk");
anatofuz
parents:
diff changeset
1206 if (s.isInPlt())
anatofuz
parents:
diff changeset
1207 return make<PPC32PltCallStub>(isec, rel, s);
anatofuz
parents:
diff changeset
1208 return make<PPC32LongThunk>(s, rel.addend);
anatofuz
parents:
diff changeset
1209 }
anatofuz
parents:
diff changeset
1210
anatofuz
parents:
diff changeset
1211 static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1212 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1213 type == R_PPC64_REL24_NOTOC) &&
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1214 "unexpected relocation type for thunk");
150
anatofuz
parents:
diff changeset
1215 if (s.isInPlt())
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1216 return type == R_PPC64_REL24_NOTOC ? (Thunk *)make<PPC64PCRelPLTStub>(s)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1217 : (Thunk *)make<PPC64PltCallStub>(s);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1218
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1219 // This check looks at the st_other bits of the callee. If the value is 1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1220 // then the callee clobbers the TOC and we need an R2 save stub when RelType
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1221 // is R_PPC64_REL14 or R_PPC64_REL24.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1222 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1223 return make<PPC64R2SaveStub>(s, a);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1224
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1225 if (type == R_PPC64_REL24_NOTOC)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1226 return (s.stOther >> 5) > 1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1227 ? (Thunk *)make<PPC64R12SetupStub>(s)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1228 : (Thunk *)make<PPC64PCRelLongBranchThunk>(s, a);
150
anatofuz
parents:
diff changeset
1229
anatofuz
parents:
diff changeset
1230 if (config->picThunk)
anatofuz
parents:
diff changeset
1231 return make<PPC64PILongBranchThunk>(s, a);
anatofuz
parents:
diff changeset
1232
anatofuz
parents:
diff changeset
1233 return make<PPC64PDLongBranchThunk>(s, a);
anatofuz
parents:
diff changeset
1234 }
anatofuz
parents:
diff changeset
1235
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1236 Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
150
anatofuz
parents:
diff changeset
1237 Symbol &s = *rel.sym;
anatofuz
parents:
diff changeset
1238 int64_t a = rel.addend;
anatofuz
parents:
diff changeset
1239
anatofuz
parents:
diff changeset
1240 if (config->emachine == EM_AARCH64)
anatofuz
parents:
diff changeset
1241 return addThunkAArch64(rel.type, s, a);
anatofuz
parents:
diff changeset
1242
anatofuz
parents:
diff changeset
1243 if (config->emachine == EM_ARM)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
1244 return addThunkArm(rel.type, s, a);
150
anatofuz
parents:
diff changeset
1245
anatofuz
parents:
diff changeset
1246 if (config->emachine == EM_MIPS)
anatofuz
parents:
diff changeset
1247 return addThunkMips(rel.type, s);
anatofuz
parents:
diff changeset
1248
anatofuz
parents:
diff changeset
1249 if (config->emachine == EM_PPC)
anatofuz
parents:
diff changeset
1250 return addThunkPPC32(isec, rel, s);
anatofuz
parents:
diff changeset
1251
anatofuz
parents:
diff changeset
1252 if (config->emachine == EM_PPC64)
anatofuz
parents:
diff changeset
1253 return addThunkPPC64(rel.type, s, a);
anatofuz
parents:
diff changeset
1254
anatofuz
parents:
diff changeset
1255 llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
anatofuz
parents:
diff changeset
1256 }