clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ARM.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldELF/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/liblldELF/obj/../include/lld/ELF -I /usr/src/gnu/usr.bin/clang/liblldELF/../../../llvm/lld/include -I /usr/src/gnu/usr.bin/clang/liblldELF/../../../llvm/lld/ELF -I /usr/src/gnu/usr.bin/clang/liblldELF/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/liblldELF/../include -I /usr/src/gnu/usr.bin/clang/liblldELF/obj -I /usr/src/gnu/usr.bin/clang/liblldELF/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldELF/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/liblldELF/../../../llvm/lld/ELF/Arch/ARM.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "InputFiles.h" |
10 | #include "Symbols.h" |
11 | #include "SyntheticSections.h" |
12 | #include "Target.h" |
13 | #include "Thunks.h" |
14 | #include "lld/Common/ErrorHandler.h" |
15 | #include "llvm/Object/ELF.h" |
16 | #include "llvm/Support/Endian.h" |
17 | |
18 | using namespace llvm; |
19 | using namespace llvm::support::endian; |
20 | using namespace llvm::ELF; |
21 | using namespace lld; |
22 | using namespace lld::elf; |
23 | |
24 | namespace { |
25 | class ARM final : public TargetInfo { |
26 | public: |
27 | ARM(); |
28 | uint32_t calcEFlags() const override; |
29 | RelExpr getRelExpr(RelType type, const Symbol &s, |
30 | const uint8_t *loc) const override; |
31 | RelType getDynRel(RelType type) const override; |
32 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; |
33 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; |
34 | void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; |
35 | void writePltHeader(uint8_t *buf) const override; |
36 | void writePlt(uint8_t *buf, const Symbol &sym, |
37 | uint64_t pltEntryAddr) const override; |
38 | void addPltSymbols(InputSection &isec, uint64_t off) const override; |
39 | void addPltHeaderSymbols(InputSection &isd) const override; |
40 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, |
41 | uint64_t branchAddr, const Symbol &s, |
42 | int64_t a) const override; |
43 | uint32_t getThunkSectionSpacing() const override; |
44 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; |
45 | void relocate(uint8_t *loc, const Relocation &rel, |
46 | uint64_t val) const override; |
47 | }; |
48 | } |
49 | |
50 | ARM::ARM() { |
51 | copyRel = R_ARM_COPY; |
52 | relativeRel = R_ARM_RELATIVE; |
53 | iRelativeRel = R_ARM_IRELATIVE; |
54 | gotRel = R_ARM_GLOB_DAT; |
55 | noneRel = R_ARM_NONE; |
56 | pltRel = R_ARM_JUMP_SLOT; |
57 | symbolicRel = R_ARM_ABS32; |
58 | tlsGotRel = R_ARM_TLS_TPOFF32; |
59 | tlsModuleIndexRel = R_ARM_TLS_DTPMOD32; |
60 | tlsOffsetRel = R_ARM_TLS_DTPOFF32; |
61 | gotBaseSymInGotPlt = false; |
62 | pltHeaderSize = 32; |
63 | pltEntrySize = 16; |
64 | ipltEntrySize = 16; |
65 | trapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; |
66 | needsThunks = true; |
67 | defaultMaxPageSize = 65536; |
68 | } |
69 | |
70 | uint32_t ARM::calcEFlags() const { |
71 | |
72 | |
73 | uint32_t abiFloatType = 0; |
74 | if (config->armVFPArgs == ARMVFPArgKind::Base || |
75 | config->armVFPArgs == ARMVFPArgKind::Default) |
76 | abiFloatType = EF_ARM_ABI_FLOAT_SOFT; |
77 | else if (config->armVFPArgs == ARMVFPArgKind::VFP) |
78 | abiFloatType = EF_ARM_ABI_FLOAT_HARD; |
79 | |
80 | |
81 | |
82 | |
83 | return EF_ARM_EABI_VER5 | abiFloatType; |
84 | } |
85 | |
86 | RelExpr ARM::getRelExpr(RelType type, const Symbol &s, |
87 | const uint8_t *loc) const { |
88 | switch (type) { |
89 | case R_ARM_THM_JUMP11: |
90 | return R_PC; |
91 | case R_ARM_CALL: |
92 | case R_ARM_JUMP24: |
93 | case R_ARM_PC24: |
94 | case R_ARM_PLT32: |
95 | case R_ARM_PREL31: |
96 | case R_ARM_THM_JUMP19: |
97 | case R_ARM_THM_JUMP24: |
98 | case R_ARM_THM_CALL: |
99 | return R_PLT_PC; |
100 | case R_ARM_GOTOFF32: |
101 | |
102 | return R_GOTREL; |
103 | case R_ARM_GOT_BREL: |
104 | |
105 | return R_GOT_OFF; |
106 | case R_ARM_GOT_PREL: |
107 | case R_ARM_TLS_IE32: |
108 | |
109 | return R_GOT_PC; |
110 | case R_ARM_SBREL32: |
111 | return R_ARM_SBREL; |
112 | case R_ARM_TARGET1: |
113 | return config->target1Rel ? R_PC : R_ABS; |
114 | case R_ARM_TARGET2: |
115 | if (config->target2 == Target2Policy::Rel) |
116 | return R_PC; |
117 | if (config->target2 == Target2Policy::Abs) |
118 | return R_ABS; |
119 | return R_GOT_PC; |
120 | case R_ARM_TLS_GD32: |
121 | return R_TLSGD_PC; |
122 | case R_ARM_TLS_LDM32: |
123 | return R_TLSLD_PC; |
124 | case R_ARM_TLS_LDO32: |
125 | return R_DTPREL; |
126 | case R_ARM_BASE_PREL: |
127 | |
128 | |
129 | |
130 | return R_GOTONLY_PC; |
131 | case R_ARM_MOVW_PREL_NC: |
132 | case R_ARM_MOVT_PREL: |
133 | case R_ARM_REL32: |
134 | case R_ARM_THM_MOVW_PREL_NC: |
135 | case R_ARM_THM_MOVT_PREL: |
136 | return R_PC; |
137 | case R_ARM_ALU_PC_G0: |
138 | case R_ARM_LDR_PC_G0: |
139 | case R_ARM_THM_ALU_PREL_11_0: |
140 | case R_ARM_THM_PC8: |
141 | case R_ARM_THM_PC12: |
142 | return R_ARM_PCA; |
143 | case R_ARM_MOVW_BREL_NC: |
144 | case R_ARM_MOVW_BREL: |
145 | case R_ARM_MOVT_BREL: |
146 | case R_ARM_THM_MOVW_BREL_NC: |
147 | case R_ARM_THM_MOVW_BREL: |
148 | case R_ARM_THM_MOVT_BREL: |
149 | return R_ARM_SBREL; |
150 | case R_ARM_NONE: |
151 | return R_NONE; |
152 | case R_ARM_TLS_LE32: |
153 | return R_TPREL; |
154 | case R_ARM_V4BX: |
155 | |
156 | |
157 | |
158 | |
159 | return R_NONE; |
160 | default: |
161 | return R_ABS; |
162 | } |
163 | } |
164 | |
165 | RelType ARM::getDynRel(RelType type) const { |
166 | if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel)) |
167 | return R_ARM_ABS32; |
168 | return R_ARM_NONE; |
169 | } |
170 | |
171 | void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { |
172 | write32le(buf, in.plt->getVA()); |
173 | } |
174 | |
175 | void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { |
176 | |
177 | write32le(buf, s.getVA()); |
178 | } |
179 | |
180 | |
181 | |
182 | static void writePltHeaderLong(uint8_t *buf) { |
183 | const uint8_t pltData[] = { |
184 | 0x04, 0xe0, 0x2d, 0xe5, |
185 | 0x04, 0xe0, 0x9f, 0xe5, |
186 | 0x0e, 0xe0, 0x8f, 0xe0, |
187 | 0x08, 0xf0, 0xbe, 0xe5, |
188 | 0x00, 0x00, 0x00, 0x00, |
189 | 0xd4, 0xd4, 0xd4, 0xd4, |
190 | 0xd4, 0xd4, 0xd4, 0xd4, |
191 | 0xd4, 0xd4, 0xd4, 0xd4}; |
192 | memcpy(buf, pltData, sizeof(pltData)); |
193 | uint64_t gotPlt = in.gotPlt->getVA(); |
194 | uint64_t l1 = in.plt->getVA() + 8; |
195 | write32le(buf + 16, gotPlt - l1 - 8); |
196 | } |
197 | |
198 | |
199 | |
200 | void ARM::writePltHeader(uint8_t *buf) const { |
201 | |
202 | |
203 | |
204 | |
205 | const uint32_t pltData[] = { |
206 | 0xe52de004, |
207 | 0xe28fe600, |
208 | 0xe28eea00, |
209 | 0xe5bef000, |
210 | }; |
211 | |
212 | uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4; |
213 | if (!llvm::isUInt<27>(offset)) { |
214 | |
215 | writePltHeaderLong(buf); |
216 | return; |
217 | } |
218 | write32le(buf + 0, pltData[0]); |
219 | write32le(buf + 4, pltData[1] | ((offset >> 20) & 0xff)); |
220 | write32le(buf + 8, pltData[2] | ((offset >> 12) & 0xff)); |
221 | write32le(buf + 12, pltData[3] | (offset & 0xfff)); |
222 | memcpy(buf + 16, trapInstr.data(), 4); |
223 | memcpy(buf + 20, trapInstr.data(), 4); |
224 | memcpy(buf + 24, trapInstr.data(), 4); |
225 | memcpy(buf + 28, trapInstr.data(), 4); |
226 | } |
227 | |
228 | void ARM::addPltHeaderSymbols(InputSection &isec) const { |
229 | addSyntheticLocal("$a", STT_NOTYPE, 0, 0, isec); |
230 | addSyntheticLocal("$d", STT_NOTYPE, 16, 0, isec); |
231 | } |
232 | |
233 | |
234 | |
235 | static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr, |
236 | uint64_t pltEntryAddr) { |
237 | const uint8_t pltData[] = { |
238 | 0x04, 0xc0, 0x9f, 0xe5, |
239 | 0x0f, 0xc0, 0x8c, 0xe0, |
240 | 0x00, 0xf0, 0x9c, 0xe5, |
241 | 0x00, 0x00, 0x00, 0x00, |
242 | }; |
243 | memcpy(buf, pltData, sizeof(pltData)); |
244 | uint64_t l1 = pltEntryAddr + 4; |
245 | write32le(buf + 12, gotPltEntryAddr - l1 - 8); |
246 | } |
247 | |
248 | |
249 | |
250 | void ARM::writePlt(uint8_t *buf, const Symbol &sym, |
251 | uint64_t pltEntryAddr) const { |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | const uint32_t pltData[] = { |
258 | 0xe28fc600, |
259 | 0xe28cca00, |
260 | 0xe5bcf000, |
261 | }; |
262 | |
263 | uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8; |
264 | if (!llvm::isUInt<27>(offset)) { |
265 | |
266 | writePltLong(buf, sym.getGotPltVA(), pltEntryAddr); |
267 | return; |
268 | } |
269 | write32le(buf + 0, pltData[0] | ((offset >> 20) & 0xff)); |
270 | write32le(buf + 4, pltData[1] | ((offset >> 12) & 0xff)); |
271 | write32le(buf + 8, pltData[2] | (offset & 0xfff)); |
272 | memcpy(buf + 12, trapInstr.data(), 4); |
273 | } |
274 | |
275 | void ARM::addPltSymbols(InputSection &isec, uint64_t off) const { |
276 | addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec); |
277 | addSyntheticLocal("$d", STT_NOTYPE, off + 12, 0, isec); |
278 | } |
279 | |
280 | bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, |
281 | uint64_t branchAddr, const Symbol &s, |
282 | int64_t a) const { |
283 | |
284 | |
285 | if (s.isUndefWeak() && !s.isInPlt()) |
286 | return false; |
287 | |
288 | |
289 | |
290 | switch (type) { |
291 | case R_ARM_PC24: |
292 | case R_ARM_PLT32: |
293 | case R_ARM_JUMP24: |
294 | |
295 | |
296 | if (s.isFunc() && expr == R_PC && (s.getVA() & 1)) |
297 | return true; |
298 | LLVM_FALLTHROUGH; |
299 | case R_ARM_CALL: { |
300 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); |
301 | return !inBranchRange(type, branchAddr, dst + a); |
302 | } |
303 | case R_ARM_THM_JUMP19: |
304 | case R_ARM_THM_JUMP24: |
305 | |
306 | |
307 | if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0)) |
308 | return true; |
309 | LLVM_FALLTHROUGH; |
310 | case R_ARM_THM_CALL: { |
311 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); |
312 | return !inBranchRange(type, branchAddr, dst + a); |
313 | } |
314 | } |
315 | return false; |
316 | } |
317 | |
318 | uint32_t ARM::getThunkSectionSpacing() const { |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | |
348 | return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000 |
349 | : 0x400000 - 0x7500; |
350 | } |
351 | |
352 | bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { |
353 | if ((dst & 0x1) == 0) |
354 | |
355 | |
356 | |
357 | src &= ~0x3; |
358 | else |
359 | |
360 | dst &= ~0x1; |
361 | |
362 | int64_t offset = dst - src; |
363 | switch (type) { |
364 | case R_ARM_PC24: |
365 | case R_ARM_PLT32: |
366 | case R_ARM_JUMP24: |
367 | case R_ARM_CALL: |
368 | return llvm::isInt<26>(offset); |
369 | case R_ARM_THM_JUMP19: |
370 | return llvm::isInt<21>(offset); |
371 | case R_ARM_THM_JUMP24: |
372 | case R_ARM_THM_CALL: |
373 | return config->armJ1J2BranchEncoding ? llvm::isInt<25>(offset) |
374 | : llvm::isInt<23>(offset); |
375 | default: |
376 | return true; |
377 | } |
378 | } |
379 | |
380 | |
381 | |
382 | |
383 | static void stateChangeWarning(uint8_t *loc, RelType relt, const Symbol &s) { |
384 | assert(!s.isFunc()); |
385 | if (s.isSection()) { |
386 | |
387 | |
388 | warn(getErrorLocation(loc) + "branch and link relocation: " + |
389 | toString(relt) + " to STT_SECTION symbol " + |
390 | cast<Defined>(s).section->name + " ; interworking not performed"); |
391 | } else { |
392 | |
393 | warn(getErrorLocation(loc) + "branch and link relocation: " + |
394 | toString(relt) + " to non STT_FUNC symbol: " + s.getName() + |
395 | " interworking not performed; consider using directive '.type " + |
396 | s.getName() + |
397 | ", %function' to give symbol type STT_FUNC if" |
398 | " interworking between ARM and Thumb is required"); |
399 | } |
400 | } |
401 | |
402 | |
403 | |
404 | |
405 | |
406 | static uint32_t rotr32(uint32_t val, uint32_t amt) { |
407 | assert(amt < 32 && "Invalid rotate amount"); |
408 | return (val >> amt) | (val << ((32 - amt) & 31)); |
| 12 | | The result of the right shift is undefined due to shifting by '32', which is greater or equal to the width of type 'uint32_t' |
|
409 | } |
410 | |
411 | |
412 | static uint32_t rotl32(uint32_t val, uint32_t amt) { |
413 | assert(amt < 32 && "Invalid rotate amount"); |
414 | return (val << amt) | (val >> ((32 - amt) & 31)); |
415 | } |
416 | |
417 | |
418 | |
419 | |
420 | |
421 | |
422 | static uint32_t getSOImmValRotate(uint32_t imm) { |
423 | |
424 | |
425 | if ((imm & ~255U) == 0) |
| 7 | | Assuming the condition is false | |
|
| |
426 | return 0; |
427 | |
428 | |
429 | unsigned tz = llvm::countTrailingZeros(imm); |
430 | |
431 | |
432 | |
433 | unsigned rotAmt = tz & ~1; |
| 9 | | 'rotAmt' initialized to 32 | |
|
434 | |
435 | |
436 | if ((rotr32(imm, rotAmt) & ~255U) == 0) |
| 10 | | Passing the value 32 via 2nd parameter 'amt' | |
|
| |
437 | return (32 - rotAmt) & 31; |
438 | |
439 | |
440 | |
441 | if (imm & 63U) { |
442 | unsigned tz2 = countTrailingZeros(imm & ~63U); |
443 | unsigned rotAmt2 = tz2 & ~1; |
444 | if ((rotr32(imm, rotAmt2) & ~255U) == 0) |
445 | return (32 - rotAmt2) & 31; |
446 | } |
447 | |
448 | |
449 | |
450 | |
451 | return (32 - rotAmt) & 31; |
452 | } |
453 | |
454 | void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { |
455 | switch (rel.type) { |
| 1 | Control jumps to 'case R_ARM_ALU_PC_G0:' at line 618 | |
|
456 | case R_ARM_ABS32: |
457 | case R_ARM_BASE_PREL: |
458 | case R_ARM_GOTOFF32: |
459 | case R_ARM_GOT_BREL: |
460 | case R_ARM_GOT_PREL: |
461 | case R_ARM_REL32: |
462 | case R_ARM_RELATIVE: |
463 | case R_ARM_SBREL32: |
464 | case R_ARM_TARGET1: |
465 | case R_ARM_TARGET2: |
466 | case R_ARM_TLS_GD32: |
467 | case R_ARM_TLS_IE32: |
468 | case R_ARM_TLS_LDM32: |
469 | case R_ARM_TLS_LDO32: |
470 | case R_ARM_TLS_LE32: |
471 | case R_ARM_TLS_TPOFF32: |
472 | case R_ARM_TLS_DTPOFF32: |
473 | write32le(loc, val); |
474 | break; |
475 | case R_ARM_PREL31: |
476 | checkInt(loc, val, 31, rel); |
477 | write32le(loc, (read32le(loc) & 0x80000000) | (val & ~0x80000000)); |
478 | break; |
479 | case R_ARM_CALL: { |
480 | |
481 | |
482 | |
483 | |
484 | |
485 | assert(rel.sym); |
486 | bool bit0Thumb = val & 1; |
487 | bool isBlx = (read32le(loc) & 0xfe000000) == 0xfa000000; |
488 | |
489 | |
490 | if (!rel.sym->isFunc() && isBlx != bit0Thumb) |
491 | stateChangeWarning(loc, rel.type, *rel.sym); |
492 | if (rel.sym->isFunc() ? bit0Thumb : isBlx) { |
493 | |
494 | checkInt(loc, val, 26, rel); |
495 | write32le(loc, 0xfa000000 | |
496 | ((val & 2) << 23) | |
497 | ((val >> 2) & 0x00ffffff)); |
498 | break; |
499 | } |
500 | |
501 | |
502 | write32le(loc, 0xeb000000 | (read32le(loc) & 0x00ffffff)); |
503 | |
504 | } |
505 | LLVM_FALLTHROUGH; |
506 | case R_ARM_JUMP24: |
507 | case R_ARM_PC24: |
508 | case R_ARM_PLT32: |
509 | checkInt(loc, val, 26, rel); |
510 | write32le(loc, (read32le(loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff)); |
511 | break; |
512 | case R_ARM_THM_JUMP11: |
513 | checkInt(loc, val, 12, rel); |
514 | write16le(loc, (read32le(loc) & 0xf800) | ((val >> 1) & 0x07ff)); |
515 | break; |
516 | case R_ARM_THM_JUMP19: |
517 | |
518 | checkInt(loc, val, 21, rel); |
519 | write16le(loc, |
520 | (read16le(loc) & 0xfbc0) | |
521 | ((val >> 10) & 0x0400) | |
522 | ((val >> 12) & 0x003f)); |
523 | write16le(loc + 2, |
524 | 0x8000 | |
525 | ((val >> 8) & 0x0800) | |
526 | ((val >> 5) & 0x2000) | |
527 | ((val >> 1) & 0x07ff)); |
528 | break; |
529 | case R_ARM_THM_CALL: { |
530 | |
531 | |
532 | |
533 | |
534 | |
535 | assert(rel.sym); |
536 | bool bit0Thumb = val & 1; |
537 | bool isBlx = (read16le(loc + 2) & 0x1000) == 0; |
538 | |
539 | |
540 | if (!rel.sym->isFunc() && !rel.sym->isInPlt() && isBlx == bit0Thumb) |
541 | stateChangeWarning(loc, rel.type, *rel.sym); |
542 | if (rel.sym->isFunc() || rel.sym->isInPlt() ? !bit0Thumb : isBlx) { |
543 | |
544 | |
545 | |
546 | val = alignTo(val, 4); |
547 | write16le(loc + 2, read16le(loc + 2) & ~0x1000); |
548 | } else { |
549 | write16le(loc + 2, (read16le(loc + 2) & ~0x1000) | 1 << 12); |
550 | } |
551 | if (!config->armJ1J2BranchEncoding) { |
552 | |
553 | |
554 | checkInt(loc, val, 23, rel); |
555 | write16le(loc, |
556 | 0xf000 | |
557 | ((val >> 12) & 0x07ff)); |
558 | write16le(loc + 2, |
559 | (read16le(loc + 2) & 0xd000) | |
560 | 0x2800 | |
561 | ((val >> 1) & 0x07ff)); |
562 | break; |
563 | } |
564 | } |
565 | |
566 | LLVM_FALLTHROUGH; |
567 | case R_ARM_THM_JUMP24: |
568 | |
569 | checkInt(loc, val, 25, rel); |
570 | write16le(loc, |
571 | 0xf000 | |
572 | ((val >> 14) & 0x0400) | |
573 | ((val >> 12) & 0x03ff)); |
574 | write16le(loc + 2, |
575 | (read16le(loc + 2) & 0xd000) | |
576 | (((~(val >> 10)) ^ (val >> 11)) & 0x2000) | |
577 | (((~(val >> 11)) ^ (val >> 13)) & 0x0800) | |
578 | ((val >> 1) & 0x07ff)); |
579 | break; |
580 | case R_ARM_MOVW_ABS_NC: |
581 | case R_ARM_MOVW_PREL_NC: |
582 | case R_ARM_MOVW_BREL_NC: |
583 | write32le(loc, (read32le(loc) & ~0x000f0fff) | ((val & 0xf000) << 4) | |
584 | (val & 0x0fff)); |
585 | break; |
586 | case R_ARM_MOVT_ABS: |
587 | case R_ARM_MOVT_PREL: |
588 | case R_ARM_MOVT_BREL: |
589 | write32le(loc, (read32le(loc) & ~0x000f0fff) | |
590 | (((val >> 16) & 0xf000) << 4) | ((val >> 16) & 0xfff)); |
591 | break; |
592 | case R_ARM_THM_MOVT_ABS: |
593 | case R_ARM_THM_MOVT_PREL: |
594 | case R_ARM_THM_MOVT_BREL: |
595 | |
596 | write16le(loc, |
597 | 0xf2c0 | |
598 | ((val >> 17) & 0x0400) | |
599 | ((val >> 28) & 0x000f)); |
600 | write16le(loc + 2, |
601 | (read16le(loc + 2) & 0x8f00) | |
602 | ((val >> 12) & 0x7000) | |
603 | ((val >> 16) & 0x00ff)); |
604 | break; |
605 | case R_ARM_THM_MOVW_ABS_NC: |
606 | case R_ARM_THM_MOVW_PREL_NC: |
607 | case R_ARM_THM_MOVW_BREL_NC: |
608 | |
609 | write16le(loc, |
610 | 0xf240 | |
611 | ((val >> 1) & 0x0400) | |
612 | ((val >> 12) & 0x000f)); |
613 | write16le(loc + 2, |
614 | (read16le(loc + 2) & 0x8f00) | |
615 | ((val << 4) & 0x7000) | |
616 | (val & 0x00ff)); |
617 | break; |
618 | case R_ARM_ALU_PC_G0: { |
619 | |
620 | |
621 | |
622 | |
623 | |
624 | uint32_t opcode = 0x00800000; |
625 | if (val >> 63) { |
| 2 | | Assuming the condition is false | |
|
| |
626 | opcode = 0x00400000; |
627 | val = ~val + 1; |
628 | } |
629 | if ((val & ~255U) != 0) { |
| 4 | | Assuming the condition is true | |
|
| |
630 | uint32_t rotAmt = getSOImmValRotate(val); |
| 6 | | Calling 'getSOImmValRotate' | |
|
631 | |
632 | if (rotr32(~255U, rotAmt) & val) |
633 | error(getErrorLocation(loc) + "unencodeable immediate " + |
634 | Twine(val).str() + " for relocation " + toString(rel.type)); |
635 | val = rotl32(val, rotAmt) | ((rotAmt >> 1) << 8); |
636 | } |
637 | write32le(loc, (read32le(loc) & 0xff0ff000) | opcode | val); |
638 | break; |
639 | } |
640 | case R_ARM_LDR_PC_G0: { |
641 | |
642 | |
643 | |
644 | if (rel.sym->isFunc()) |
645 | val &= ~0x1; |
646 | |
647 | int64_t imm = val; |
648 | uint32_t u = 0x00800000; |
649 | if (imm < 0) { |
650 | imm = -imm; |
651 | u = 0; |
652 | } |
653 | checkUInt(loc, imm, 12, rel); |
654 | write32le(loc, (read32le(loc) & 0xff7ff000) | u | imm); |
655 | break; |
656 | } |
657 | case R_ARM_THM_ALU_PREL_11_0: { |
658 | |
659 | int64_t imm = val; |
660 | uint16_t sub = 0; |
661 | if (imm < 0) { |
662 | imm = -imm; |
663 | sub = 0x00a0; |
664 | } |
665 | checkUInt(loc, imm, 12, rel); |
666 | write16le(loc, (read16le(loc) & 0xfb0f) | sub | (imm & 0x800) >> 1); |
667 | write16le(loc + 2, |
668 | (read16le(loc + 2) & 0x8f00) | (imm & 0x700) << 4 | (imm & 0xff)); |
669 | break; |
670 | } |
671 | case R_ARM_THM_PC8: |
672 | |
673 | |
674 | |
675 | |
676 | if (rel.sym->isFunc()) |
677 | val &= ~0x1; |
678 | checkUInt(loc, val, 10, rel); |
679 | checkAlignment(loc, val, 4, rel); |
680 | write16le(loc, (read16le(loc) & 0xff00) | (val & 0x3fc) >> 2); |
681 | break; |
682 | case R_ARM_THM_PC12: { |
683 | |
684 | |
685 | |
686 | |
687 | |
688 | if (rel.sym->isFunc()) |
689 | val &= ~0x1; |
690 | int64_t imm12 = val; |
691 | uint16_t u = 0x0080; |
692 | if (imm12 < 0) { |
693 | imm12 = -imm12; |
694 | u = 0; |
695 | } |
696 | checkUInt(loc, imm12, 12, rel); |
697 | write16le(loc, read16le(loc) | u); |
698 | write16le(loc + 2, (read16le(loc + 2) & 0xf000) | imm12); |
699 | break; |
700 | } |
701 | default: |
702 | error(getErrorLocation(loc) + "unrecognized relocation " + |
703 | toString(rel.type)); |
704 | } |
705 | } |
706 | |
707 | int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { |
708 | switch (type) { |
709 | default: |
710 | internalLinkerError(getErrorLocation(buf), |
711 | "cannot read addend for relocation " + toString(type)); |
712 | return 0; |
713 | case R_ARM_ABS32: |
714 | case R_ARM_BASE_PREL: |
715 | case R_ARM_GLOB_DAT: |
716 | case R_ARM_GOTOFF32: |
717 | case R_ARM_GOT_BREL: |
718 | case R_ARM_GOT_PREL: |
719 | case R_ARM_IRELATIVE: |
720 | case R_ARM_REL32: |
721 | case R_ARM_RELATIVE: |
722 | case R_ARM_SBREL32: |
723 | case R_ARM_TARGET1: |
724 | case R_ARM_TARGET2: |
725 | case R_ARM_TLS_DTPMOD32: |
726 | case R_ARM_TLS_DTPOFF32: |
727 | case R_ARM_TLS_GD32: |
728 | case R_ARM_TLS_IE32: |
729 | case R_ARM_TLS_LDM32: |
730 | case R_ARM_TLS_LE32: |
731 | case R_ARM_TLS_LDO32: |
732 | case R_ARM_TLS_TPOFF32: |
733 | return SignExtend64<32>(read32le(buf)); |
734 | case R_ARM_PREL31: |
735 | return SignExtend64<31>(read32le(buf)); |
736 | case R_ARM_CALL: |
737 | case R_ARM_JUMP24: |
738 | case R_ARM_PC24: |
739 | case R_ARM_PLT32: |
740 | return SignExtend64<26>(read32le(buf) << 2); |
741 | case R_ARM_THM_JUMP11: |
742 | return SignExtend64<12>(read16le(buf) << 1); |
743 | case R_ARM_THM_JUMP19: { |
744 | |
745 | uint16_t hi = read16le(buf); |
746 | uint16_t lo = read16le(buf + 2); |
747 | return SignExtend64<20>(((hi & 0x0400) << 10) | |
748 | ((lo & 0x0800) << 8) | |
749 | ((lo & 0x2000) << 5) | |
750 | ((hi & 0x003f) << 12) | |
751 | ((lo & 0x07ff) << 1)); |
752 | } |
753 | case R_ARM_THM_CALL: |
754 | if (!config->armJ1J2BranchEncoding) { |
755 | |
756 | |
757 | uint16_t hi = read16le(buf); |
758 | uint16_t lo = read16le(buf + 2); |
759 | return SignExtend64<22>(((hi & 0x7ff) << 12) | |
760 | ((lo & 0x7ff) << 1)); |
761 | break; |
762 | } |
763 | LLVM_FALLTHROUGH; |
764 | case R_ARM_THM_JUMP24: { |
765 | |
766 | |
767 | uint16_t hi = read16le(buf); |
768 | uint16_t lo = read16le(buf + 2); |
769 | return SignExtend64<24>(((hi & 0x0400) << 14) | |
770 | (~((lo ^ (hi << 3)) << 10) & 0x00800000) | |
771 | (~((lo ^ (hi << 1)) << 11) & 0x00400000) | |
772 | ((hi & 0x003ff) << 12) | |
773 | ((lo & 0x007ff) << 1)); |
774 | } |
775 | |
776 | |
777 | case R_ARM_MOVW_ABS_NC: |
778 | case R_ARM_MOVT_ABS: |
779 | case R_ARM_MOVW_PREL_NC: |
780 | case R_ARM_MOVT_PREL: |
781 | case R_ARM_MOVW_BREL_NC: |
782 | case R_ARM_MOVT_BREL: { |
783 | uint64_t val = read32le(buf) & 0x000f0fff; |
784 | return SignExtend64<16>(((val & 0x000f0000) >> 4) | (val & 0x00fff)); |
785 | } |
786 | case R_ARM_THM_MOVW_ABS_NC: |
787 | case R_ARM_THM_MOVT_ABS: |
788 | case R_ARM_THM_MOVW_PREL_NC: |
789 | case R_ARM_THM_MOVT_PREL: |
790 | case R_ARM_THM_MOVW_BREL_NC: |
791 | case R_ARM_THM_MOVT_BREL: { |
792 | |
793 | uint16_t hi = read16le(buf); |
794 | uint16_t lo = read16le(buf + 2); |
795 | return SignExtend64<16>(((hi & 0x000f) << 12) | |
796 | ((hi & 0x0400) << 1) | |
797 | ((lo & 0x7000) >> 4) | |
798 | (lo & 0x00ff)); |
799 | } |
800 | case R_ARM_ALU_PC_G0: { |
801 | |
802 | |
803 | |
804 | |
805 | uint32_t instr = read32le(buf); |
806 | uint32_t val = rotr32(instr & 0xff, ((instr & 0xf00) >> 8) * 2); |
807 | return (instr & 0x00400000) ? -val : val; |
808 | } |
809 | case R_ARM_LDR_PC_G0: { |
810 | |
811 | |
812 | bool u = read32le(buf) & 0x00800000; |
813 | uint32_t imm12 = read32le(buf) & 0xfff; |
814 | return u ? imm12 : -imm12; |
815 | } |
816 | case R_ARM_THM_ALU_PREL_11_0: { |
817 | |
818 | |
819 | |
820 | uint16_t hi = read16le(buf); |
821 | uint16_t lo = read16le(buf + 2); |
822 | uint64_t imm = (hi & 0x0400) << 1 | |
823 | (lo & 0x7000) >> 4 | |
824 | (lo & 0x00ff); |
825 | |
826 | return (hi & 0x00f0) ? -imm : imm; |
827 | } |
828 | case R_ARM_THM_PC8: |
829 | |
830 | |
831 | |
832 | |
833 | return ((((read16le(buf) & 0xff) << 2) + 4) & 0x3ff) - 4; |
834 | case R_ARM_THM_PC12: { |
835 | |
836 | bool u = read16le(buf) & 0x0080; |
837 | uint64_t imm12 = read16le(buf + 2) & 0x0fff; |
838 | return u ? imm12 : -imm12; |
839 | } |
840 | case R_ARM_NONE: |
841 | case R_ARM_JUMP_SLOT: |
842 | |
843 | return 0; |
844 | } |
845 | } |
846 | |
847 | TargetInfo *elf::getARMTargetInfo() { |
848 | static ARM target; |
849 | return ⌖ |
850 | } |