1 | //===- ARM.cpp ------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "InputFiles.h" |
10 | #include "OutputSections.h" |
11 | #include "SymbolTable.h" |
12 | #include "Symbols.h" |
13 | #include "SyntheticSections.h" |
14 | #include "Target.h" |
15 | #include "lld/Common/ErrorHandler.h" |
16 | #include "lld/Common/Filesystem.h" |
17 | #include "llvm/BinaryFormat/ELF.h" |
18 | #include "llvm/Support/Endian.h" |
19 | |
20 | using namespace llvm; |
21 | using namespace llvm::support::endian; |
22 | using namespace llvm::support; |
23 | using namespace llvm::ELF; |
24 | using namespace lld; |
25 | using namespace lld::elf; |
26 | using namespace llvm::object; |
27 | |
28 | namespace { |
29 | class ARM final : public TargetInfo { |
30 | public: |
31 | ARM(); |
32 | uint32_t calcEFlags() const override; |
33 | RelExpr getRelExpr(RelType type, const Symbol &s, |
34 | const uint8_t *loc) const override; |
35 | RelType getDynRel(RelType type) const override; |
36 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; |
37 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; |
38 | void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; |
39 | void writePltHeader(uint8_t *buf) const override; |
40 | void writePlt(uint8_t *buf, const Symbol &sym, |
41 | uint64_t pltEntryAddr) const override; |
42 | void addPltSymbols(InputSection &isec, uint64_t off) const override; |
43 | void addPltHeaderSymbols(InputSection &isd) const override; |
44 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, |
45 | uint64_t branchAddr, const Symbol &s, |
46 | int64_t a) const override; |
47 | uint32_t getThunkSectionSpacing() const override; |
48 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; |
49 | void relocate(uint8_t *loc, const Relocation &rel, |
50 | uint64_t val) const override; |
51 | }; |
52 | enum class CodeState { Data = 0, Thumb = 2, Arm = 4 }; |
53 | } // namespace |
54 | |
55 | static DenseMap<InputSection *, SmallVector<const Defined *, 0>> sectionMap{}; |
56 | |
57 | ARM::ARM() { |
58 | copyRel = R_ARM_COPY; |
59 | relativeRel = R_ARM_RELATIVE; |
60 | iRelativeRel = R_ARM_IRELATIVE; |
61 | gotRel = R_ARM_GLOB_DAT; |
62 | pltRel = R_ARM_JUMP_SLOT; |
63 | symbolicRel = R_ARM_ABS32; |
64 | tlsGotRel = R_ARM_TLS_TPOFF32; |
65 | tlsModuleIndexRel = R_ARM_TLS_DTPMOD32; |
66 | tlsOffsetRel = R_ARM_TLS_DTPOFF32; |
67 | pltHeaderSize = 32; |
68 | pltEntrySize = 16; |
69 | ipltEntrySize = 16; |
70 | trapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; |
71 | needsThunks = true; |
72 | defaultMaxPageSize = 65536; |
73 | } |
74 | |
75 | uint32_t ARM::calcEFlags() const { |
76 | // The ABIFloatType is used by loaders to detect the floating point calling |
77 | // convention. |
78 | uint32_t abiFloatType = 0; |
79 | |
80 | // Set the EF_ARM_BE8 flag in the ELF header, if ELF file is big-endian |
81 | // with BE-8 code. |
82 | uint32_t armBE8 = 0; |
83 | |
84 | if (config->armVFPArgs == ARMVFPArgKind::Base || |
85 | config->armVFPArgs == ARMVFPArgKind::Default) |
86 | abiFloatType = EF_ARM_ABI_FLOAT_SOFT; |
87 | else if (config->armVFPArgs == ARMVFPArgKind::VFP) |
88 | abiFloatType = EF_ARM_ABI_FLOAT_HARD; |
89 | |
90 | if (!config->isLE && config->armBe8) |
91 | armBE8 = EF_ARM_BE8; |
92 | |
93 | // We don't currently use any features incompatible with EF_ARM_EABI_VER5, |
94 | // but we don't have any firm guarantees of conformance. Linux AArch64 |
95 | // kernels (as of 2016) require an EABI version to be set. |
96 | return EF_ARM_EABI_VER5 | abiFloatType | armBE8; |
97 | } |
98 | |
99 | RelExpr ARM::getRelExpr(RelType type, const Symbol &s, |
100 | const uint8_t *loc) const { |
101 | switch (type) { |
102 | case R_ARM_ABS32: |
103 | case R_ARM_MOVW_ABS_NC: |
104 | case R_ARM_MOVT_ABS: |
105 | case R_ARM_THM_MOVW_ABS_NC: |
106 | case R_ARM_THM_MOVT_ABS: |
107 | case R_ARM_THM_ALU_ABS_G0_NC: |
108 | case R_ARM_THM_ALU_ABS_G1_NC: |
109 | case R_ARM_THM_ALU_ABS_G2_NC: |
110 | case R_ARM_THM_ALU_ABS_G3: |
111 | return R_ABS; |
112 | case R_ARM_THM_JUMP8: |
113 | case R_ARM_THM_JUMP11: |
114 | return R_PC; |
115 | case R_ARM_CALL: |
116 | case R_ARM_JUMP24: |
117 | case R_ARM_PC24: |
118 | case R_ARM_PLT32: |
119 | case R_ARM_PREL31: |
120 | case R_ARM_THM_JUMP19: |
121 | case R_ARM_THM_JUMP24: |
122 | case R_ARM_THM_CALL: |
123 | return R_PLT_PC; |
124 | case R_ARM_GOTOFF32: |
125 | // (S + A) - GOT_ORG |
126 | return R_GOTREL; |
127 | case R_ARM_GOT_BREL: |
128 | // GOT(S) + A - GOT_ORG |
129 | return R_GOT_OFF; |
130 | case R_ARM_GOT_PREL: |
131 | case R_ARM_TLS_IE32: |
132 | // GOT(S) + A - P |
133 | return R_GOT_PC; |
134 | case R_ARM_SBREL32: |
135 | return R_ARM_SBREL; |
136 | case R_ARM_TARGET1: |
137 | return config->target1Rel ? R_PC : R_ABS; |
138 | case R_ARM_TARGET2: |
139 | if (config->target2 == Target2Policy::Rel) |
140 | return R_PC; |
141 | if (config->target2 == Target2Policy::Abs) |
142 | return R_ABS; |
143 | return R_GOT_PC; |
144 | case R_ARM_TLS_GD32: |
145 | return R_TLSGD_PC; |
146 | case R_ARM_TLS_LDM32: |
147 | return R_TLSLD_PC; |
148 | case R_ARM_TLS_LDO32: |
149 | return R_DTPREL; |
150 | case R_ARM_BASE_PREL: |
151 | // B(S) + A - P |
152 | // FIXME: currently B(S) assumed to be .got, this may not hold for all |
153 | // platforms. |
154 | return R_GOTONLY_PC; |
155 | case R_ARM_MOVW_PREL_NC: |
156 | case R_ARM_MOVT_PREL: |
157 | case R_ARM_REL32: |
158 | case R_ARM_THM_MOVW_PREL_NC: |
159 | case R_ARM_THM_MOVT_PREL: |
160 | return R_PC; |
161 | case R_ARM_ALU_PC_G0: |
162 | case R_ARM_ALU_PC_G0_NC: |
163 | case R_ARM_ALU_PC_G1: |
164 | case R_ARM_ALU_PC_G1_NC: |
165 | case R_ARM_ALU_PC_G2: |
166 | case R_ARM_LDR_PC_G0: |
167 | case R_ARM_LDR_PC_G1: |
168 | case R_ARM_LDR_PC_G2: |
169 | case R_ARM_LDRS_PC_G0: |
170 | case R_ARM_LDRS_PC_G1: |
171 | case R_ARM_LDRS_PC_G2: |
172 | case R_ARM_THM_ALU_PREL_11_0: |
173 | case R_ARM_THM_PC8: |
174 | case R_ARM_THM_PC12: |
175 | return R_ARM_PCA; |
176 | case R_ARM_MOVW_BREL_NC: |
177 | case R_ARM_MOVW_BREL: |
178 | case R_ARM_MOVT_BREL: |
179 | case R_ARM_THM_MOVW_BREL_NC: |
180 | case R_ARM_THM_MOVW_BREL: |
181 | case R_ARM_THM_MOVT_BREL: |
182 | return R_ARM_SBREL; |
183 | case R_ARM_NONE: |
184 | return R_NONE; |
185 | case R_ARM_TLS_LE32: |
186 | return R_TPREL; |
187 | case R_ARM_V4BX: |
188 | // V4BX is just a marker to indicate there's a "bx rN" instruction at the |
189 | // given address. It can be used to implement a special linker mode which |
190 | // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and |
191 | // not ARMv4 output, we can just ignore it. |
192 | return R_NONE; |
193 | default: |
194 | error(msg: getErrorLocation(loc) + "unknown relocation (" + Twine(type) + |
195 | ") against symbol " + toString(s)); |
196 | return R_NONE; |
197 | } |
198 | } |
199 | |
200 | RelType ARM::getDynRel(RelType type) const { |
201 | if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel)) |
202 | return R_ARM_ABS32; |
203 | return R_ARM_NONE; |
204 | } |
205 | |
206 | void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { |
207 | write32(p: buf, v: in.plt->getVA()); |
208 | } |
209 | |
210 | void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { |
211 | // An ARM entry is the address of the ifunc resolver function. |
212 | write32(p: buf, v: s.getVA()); |
213 | } |
214 | |
215 | // Long form PLT Header that does not have any restrictions on the displacement |
216 | // of the .plt from the .got.plt. |
217 | static void (uint8_t *buf) { |
218 | write32(p: buf + 0, v: 0xe52de004); // str lr, [sp,#-4]! |
219 | write32(p: buf + 4, v: 0xe59fe004); // ldr lr, L2 |
220 | write32(p: buf + 8, v: 0xe08fe00e); // L1: add lr, pc, lr |
221 | write32(p: buf + 12, v: 0xe5bef008); // ldr pc, [lr, #8] |
222 | write32(p: buf + 16, v: 0x00000000); // L2: .word &(.got.plt) - L1 - 8 |
223 | write32(p: buf + 20, v: 0xd4d4d4d4); // Pad to 32-byte boundary |
224 | write32(p: buf + 24, v: 0xd4d4d4d4); // Pad to 32-byte boundary |
225 | write32(p: buf + 28, v: 0xd4d4d4d4); |
226 | uint64_t gotPlt = in.gotPlt->getVA(); |
227 | uint64_t l1 = in.plt->getVA() + 8; |
228 | write32(p: buf + 16, v: gotPlt - l1 - 8); |
229 | } |
230 | |
231 | // The default PLT header requires the .got.plt to be within 128 Mb of the |
232 | // .plt in the positive direction. |
233 | void ARM::(uint8_t *buf) const { |
234 | // Use a similar sequence to that in writePlt(), the difference is the calling |
235 | // conventions mean we use lr instead of ip. The PLT entry is responsible for |
236 | // saving lr on the stack, the dynamic loader is responsible for reloading |
237 | // it. |
238 | const uint32_t pltData[] = { |
239 | 0xe52de004, // L1: str lr, [sp,#-4]! |
240 | 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) |
241 | 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) |
242 | 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) |
243 | }; |
244 | |
245 | uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4; |
246 | if (!llvm::isUInt<27>(x: offset)) { |
247 | // We cannot encode the Offset, use the long form. |
248 | writePltHeaderLong(buf); |
249 | return; |
250 | } |
251 | write32(p: buf + 0, v: pltData[0]); |
252 | write32(p: buf + 4, v: pltData[1] | ((offset >> 20) & 0xff)); |
253 | write32(p: buf + 8, v: pltData[2] | ((offset >> 12) & 0xff)); |
254 | write32(p: buf + 12, v: pltData[3] | (offset & 0xfff)); |
255 | memcpy(dest: buf + 16, src: trapInstr.data(), n: 4); // Pad to 32-byte boundary |
256 | memcpy(dest: buf + 20, src: trapInstr.data(), n: 4); |
257 | memcpy(dest: buf + 24, src: trapInstr.data(), n: 4); |
258 | memcpy(dest: buf + 28, src: trapInstr.data(), n: 4); |
259 | } |
260 | |
261 | void ARM::(InputSection &isec) const { |
262 | addSyntheticLocal(name: "$a" , type: STT_NOTYPE, value: 0, size: 0, section&: isec); |
263 | addSyntheticLocal(name: "$d" , type: STT_NOTYPE, value: 16, size: 0, section&: isec); |
264 | } |
265 | |
266 | // Long form PLT entries that do not have any restrictions on the displacement |
267 | // of the .plt from the .got.plt. |
268 | static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr, |
269 | uint64_t pltEntryAddr) { |
270 | write32(p: buf + 0, v: 0xe59fc004); // ldr ip, L2 |
271 | write32(p: buf + 4, v: 0xe08cc00f); // L1: add ip, ip, pc |
272 | write32(p: buf + 8, v: 0xe59cf000); // ldr pc, [ip] |
273 | write32(p: buf + 12, v: 0x00000000); // L2: .word Offset(&(.got.plt) - L1 - 8 |
274 | uint64_t l1 = pltEntryAddr + 4; |
275 | write32(p: buf + 12, v: gotPltEntryAddr - l1 - 8); |
276 | } |
277 | |
278 | // The default PLT entries require the .got.plt to be within 128 Mb of the |
279 | // .plt in the positive direction. |
280 | void ARM::writePlt(uint8_t *buf, const Symbol &sym, |
281 | uint64_t pltEntryAddr) const { |
282 | // The PLT entry is similar to the example given in Appendix A of ELF for |
283 | // the Arm Architecture. Instead of using the Group Relocations to find the |
284 | // optimal rotation for the 8-bit immediate used in the add instructions we |
285 | // hard code the most compact rotations for simplicity. This saves a load |
286 | // instruction over the long plt sequences. |
287 | const uint32_t pltData[] = { |
288 | 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8 |
289 | 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8 |
290 | 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8 |
291 | }; |
292 | |
293 | uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8; |
294 | if (!llvm::isUInt<27>(x: offset)) { |
295 | // We cannot encode the Offset, use the long form. |
296 | writePltLong(buf, gotPltEntryAddr: sym.getGotPltVA(), pltEntryAddr); |
297 | return; |
298 | } |
299 | write32(p: buf + 0, v: pltData[0] | ((offset >> 20) & 0xff)); |
300 | write32(p: buf + 4, v: pltData[1] | ((offset >> 12) & 0xff)); |
301 | write32(p: buf + 8, v: pltData[2] | (offset & 0xfff)); |
302 | memcpy(dest: buf + 12, src: trapInstr.data(), n: 4); // Pad to 16-byte boundary |
303 | } |
304 | |
305 | void ARM::addPltSymbols(InputSection &isec, uint64_t off) const { |
306 | addSyntheticLocal(name: "$a" , type: STT_NOTYPE, value: off, size: 0, section&: isec); |
307 | addSyntheticLocal(name: "$d" , type: STT_NOTYPE, value: off + 12, size: 0, section&: isec); |
308 | } |
309 | |
310 | bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, |
311 | uint64_t branchAddr, const Symbol &s, |
312 | int64_t a) const { |
313 | // If s is an undefined weak symbol and does not have a PLT entry then it will |
314 | // be resolved as a branch to the next instruction. If it is hidden, its |
315 | // binding has been converted to local, so we just check isUndefined() here. A |
316 | // undefined non-weak symbol will have been errored. |
317 | if (s.isUndefined() && !s.isInPlt()) |
318 | return false; |
319 | // A state change from ARM to Thumb and vice versa must go through an |
320 | // interworking thunk if the relocation type is not R_ARM_CALL or |
321 | // R_ARM_THM_CALL. |
322 | switch (type) { |
323 | case R_ARM_PC24: |
324 | case R_ARM_PLT32: |
325 | case R_ARM_JUMP24: |
326 | // Source is ARM, all PLT entries are ARM so no interworking required. |
327 | // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb). |
328 | if (s.isFunc() && expr == R_PC && (s.getVA() & 1)) |
329 | return true; |
330 | [[fallthrough]]; |
331 | case R_ARM_CALL: { |
332 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); |
333 | return !inBranchRange(type, src: branchAddr, dst: dst + a) || |
334 | (!config->armHasBlx && (s.getVA() & 1)); |
335 | } |
336 | case R_ARM_THM_JUMP19: |
337 | case R_ARM_THM_JUMP24: |
338 | // Source is Thumb, all PLT entries are ARM so interworking is required. |
339 | // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM). |
340 | if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0)) |
341 | return true; |
342 | [[fallthrough]]; |
343 | case R_ARM_THM_CALL: { |
344 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); |
345 | return !inBranchRange(type, src: branchAddr, dst: dst + a) || |
346 | (!config->armHasBlx && (s.getVA() & 1) == 0);; |
347 | } |
348 | } |
349 | return false; |
350 | } |
351 | |
352 | uint32_t ARM::getThunkSectionSpacing() const { |
353 | // The placing of pre-created ThunkSections is controlled by the value |
354 | // thunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to |
355 | // place the ThunkSection such that all branches from the InputSections |
356 | // prior to the ThunkSection can reach a Thunk placed at the end of the |
357 | // ThunkSection. Graphically: |
358 | // | up to thunkSectionSpacing .text input sections | |
359 | // | ThunkSection | |
360 | // | up to thunkSectionSpacing .text input sections | |
361 | // | ThunkSection | |
362 | |
363 | // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This |
364 | // is to match the most common expected case of a Thumb 2 encoded BL, BLX or |
365 | // B.W: |
366 | // ARM B, BL, BLX range +/- 32MiB |
367 | // Thumb B.W, BL, BLX range +/- 16MiB |
368 | // Thumb B<cc>.W range +/- 1MiB |
369 | // If a branch cannot reach a pre-created ThunkSection a new one will be |
370 | // created so we can handle the rare cases of a Thumb 2 conditional branch. |
371 | // We intentionally use a lower size for thunkSectionSpacing than the maximum |
372 | // branch range so the end of the ThunkSection is more likely to be within |
373 | // range of the branch instruction that is furthest away. The value we shorten |
374 | // thunkSectionSpacing by is set conservatively to allow us to create 16,384 |
375 | // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to |
376 | // one of the Thunks going out of range. |
377 | |
378 | // On Arm the thunkSectionSpacing depends on the range of the Thumb Branch |
379 | // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except |
380 | // ARMv6T2) the range is +/- 4MiB. |
381 | |
382 | return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000 |
383 | : 0x400000 - 0x7500; |
384 | } |
385 | |
386 | bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { |
387 | if ((dst & 0x1) == 0) |
388 | // Destination is ARM, if ARM caller then Src is already 4-byte aligned. |
389 | // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure |
390 | // destination will be 4 byte aligned. |
391 | src &= ~0x3; |
392 | else |
393 | // Bit 0 == 1 denotes Thumb state, it is not part of the range. |
394 | dst &= ~0x1; |
395 | |
396 | int64_t offset = dst - src; |
397 | switch (type) { |
398 | case R_ARM_PC24: |
399 | case R_ARM_PLT32: |
400 | case R_ARM_JUMP24: |
401 | case R_ARM_CALL: |
402 | return llvm::isInt<26>(x: offset); |
403 | case R_ARM_THM_JUMP19: |
404 | return llvm::isInt<21>(x: offset); |
405 | case R_ARM_THM_JUMP24: |
406 | case R_ARM_THM_CALL: |
407 | return config->armJ1J2BranchEncoding ? llvm::isInt<25>(x: offset) |
408 | : llvm::isInt<23>(x: offset); |
409 | default: |
410 | return true; |
411 | } |
412 | } |
413 | |
414 | // Helper to produce message text when LLD detects that a CALL relocation to |
415 | // a non STT_FUNC symbol that may result in incorrect interworking between ARM |
416 | // or Thumb. |
417 | static void stateChangeWarning(uint8_t *loc, RelType relt, const Symbol &s) { |
418 | assert(!s.isFunc()); |
419 | const ErrorPlace place = getErrorPlace(loc); |
420 | std::string hint; |
421 | if (!place.srcLoc.empty()) |
422 | hint = "; " + place.srcLoc; |
423 | if (s.isSection()) { |
424 | // Section symbols must be defined and in a section. Users cannot change |
425 | // the type. Use the section name as getName() returns an empty string. |
426 | warn(msg: place.loc + "branch and link relocation: " + toString(type: relt) + |
427 | " to STT_SECTION symbol " + cast<Defined>(Val: s).section->name + |
428 | " ; interworking not performed" + hint); |
429 | } else { |
430 | // Warn with hint on how to alter the symbol type. |
431 | warn(msg: getErrorLocation(loc) + "branch and link relocation: " + |
432 | toString(type: relt) + " to non STT_FUNC symbol: " + s.getName() + |
433 | " interworking not performed; consider using directive '.type " + |
434 | s.getName() + |
435 | ", %function' to give symbol type STT_FUNC if interworking between " |
436 | "ARM and Thumb is required" + |
437 | hint); |
438 | } |
439 | } |
440 | |
441 | // Rotate a 32-bit unsigned value right by a specified amt of bits. |
442 | static uint32_t rotr32(uint32_t val, uint32_t amt) { |
443 | assert(amt < 32 && "Invalid rotate amount" ); |
444 | return (val >> amt) | (val << ((32 - amt) & 31)); |
445 | } |
446 | |
447 | static std::pair<uint32_t, uint32_t> getRemAndLZForGroup(unsigned group, |
448 | uint32_t val) { |
449 | uint32_t rem, lz; |
450 | do { |
451 | lz = llvm::countl_zero(Val: val) & ~1; |
452 | rem = val; |
453 | if (lz == 32) // implies rem == 0 |
454 | break; |
455 | val &= 0xffffff >> lz; |
456 | } while (group--); |
457 | return {rem, lz}; |
458 | } |
459 | |
460 | static void encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val, |
461 | int group, bool check) { |
462 | // ADD/SUB (immediate) add = bit23, sub = bit22 |
463 | // immediate field carries is a 12-bit modified immediate, made up of a 4-bit |
464 | // even rotate right and an 8-bit immediate. |
465 | uint32_t opcode = 0x00800000; |
466 | if (val >> 63) { |
467 | opcode = 0x00400000; |
468 | val = -val; |
469 | } |
470 | uint32_t imm, lz; |
471 | std::tie(args&: imm, args&: lz) = getRemAndLZForGroup(group, val); |
472 | uint32_t rot = 0; |
473 | if (lz < 24) { |
474 | imm = rotr32(val: imm, amt: 24 - lz); |
475 | rot = (lz + 8) << 7; |
476 | } |
477 | if (check && imm > 0xff) |
478 | error(msg: getErrorLocation(loc) + "unencodeable immediate " + Twine(val).str() + |
479 | " for relocation " + toString(type: rel.type)); |
480 | write32(p: loc, v: (read32(p: loc) & 0xff3ff000) | opcode | rot | (imm & 0xff)); |
481 | } |
482 | |
483 | static void encodeLdrGroup(uint8_t *loc, const Relocation &rel, uint64_t val, |
484 | int group) { |
485 | // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a |
486 | // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear |
487 | // bottom bit to recover S + A - P. |
488 | if (rel.sym->isFunc()) |
489 | val &= ~0x1; |
490 | // LDR (literal) u = bit23 |
491 | uint32_t opcode = 0x00800000; |
492 | if (val >> 63) { |
493 | opcode = 0x0; |
494 | val = -val; |
495 | } |
496 | uint32_t imm = getRemAndLZForGroup(group, val).first; |
497 | checkUInt(loc, v: imm, n: 12, rel); |
498 | write32(p: loc, v: (read32(p: loc) & 0xff7ff000) | opcode | imm); |
499 | } |
500 | |
501 | static void encodeLdrsGroup(uint8_t *loc, const Relocation &rel, uint64_t val, |
502 | int group) { |
503 | // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a |
504 | // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear |
505 | // bottom bit to recover S + A - P. |
506 | if (rel.sym->isFunc()) |
507 | val &= ~0x1; |
508 | // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23 |
509 | uint32_t opcode = 0x00800000; |
510 | if (val >> 63) { |
511 | opcode = 0x0; |
512 | val = -val; |
513 | } |
514 | uint32_t imm = getRemAndLZForGroup(group, val).first; |
515 | checkUInt(loc, v: imm, n: 8, rel); |
516 | write32(p: loc, v: (read32(p: loc) & 0xff7ff0f0) | opcode | ((imm & 0xf0) << 4) | |
517 | (imm & 0xf)); |
518 | } |
519 | |
520 | void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { |
521 | switch (rel.type) { |
522 | case R_ARM_ABS32: |
523 | case R_ARM_BASE_PREL: |
524 | case R_ARM_GOTOFF32: |
525 | case R_ARM_GOT_BREL: |
526 | case R_ARM_GOT_PREL: |
527 | case R_ARM_REL32: |
528 | case R_ARM_RELATIVE: |
529 | case R_ARM_SBREL32: |
530 | case R_ARM_TARGET1: |
531 | case R_ARM_TARGET2: |
532 | case R_ARM_TLS_GD32: |
533 | case R_ARM_TLS_IE32: |
534 | case R_ARM_TLS_LDM32: |
535 | case R_ARM_TLS_LDO32: |
536 | case R_ARM_TLS_LE32: |
537 | case R_ARM_TLS_TPOFF32: |
538 | case R_ARM_TLS_DTPOFF32: |
539 | write32(p: loc, v: val); |
540 | break; |
541 | case R_ARM_PREL31: |
542 | checkInt(loc, v: val, n: 31, rel); |
543 | write32(p: loc, v: (read32(p: loc) & 0x80000000) | (val & ~0x80000000)); |
544 | break; |
545 | case R_ARM_CALL: { |
546 | // R_ARM_CALL is used for BL and BLX instructions, for symbols of type |
547 | // STT_FUNC we choose whether to write a BL or BLX depending on the |
548 | // value of bit 0 of Val. With bit 0 == 1 denoting Thumb. If the symbol is |
549 | // not of type STT_FUNC then we must preserve the original instruction. |
550 | // PLT entries are always ARM state so we know we don't need to interwork. |
551 | assert(rel.sym); // R_ARM_CALL is always reached via relocate(). |
552 | bool bit0Thumb = val & 1; |
553 | bool isBlx = (read32(p: loc) & 0xfe000000) == 0xfa000000; |
554 | // lld 10.0 and before always used bit0Thumb when deciding to write a BLX |
555 | // even when type not STT_FUNC. |
556 | if (!rel.sym->isFunc() && isBlx != bit0Thumb) |
557 | stateChangeWarning(loc, relt: rel.type, s: *rel.sym); |
558 | if (rel.sym->isFunc() ? bit0Thumb : isBlx) { |
559 | // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' |
560 | checkInt(loc, v: val, n: 26, rel); |
561 | write32(p: loc, v: 0xfa000000 | // opcode |
562 | ((val & 2) << 23) | // H |
563 | ((val >> 2) & 0x00ffffff)); // imm24 |
564 | break; |
565 | } |
566 | // BLX (always unconditional) instruction to an ARM Target, select an |
567 | // unconditional BL. |
568 | write32(p: loc, v: 0xeb000000 | (read32(p: loc) & 0x00ffffff)); |
569 | // fall through as BL encoding is shared with B |
570 | } |
571 | [[fallthrough]]; |
572 | case R_ARM_JUMP24: |
573 | case R_ARM_PC24: |
574 | case R_ARM_PLT32: |
575 | checkInt(loc, v: val, n: 26, rel); |
576 | write32(p: loc, v: (read32(p: loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff)); |
577 | break; |
578 | case R_ARM_THM_JUMP8: |
579 | // We do a 9 bit check because val is right-shifted by 1 bit. |
580 | checkInt(loc, v: val, n: 9, rel); |
581 | write16(p: loc, v: (read32(p: loc) & 0xff00) | ((val >> 1) & 0x00ff)); |
582 | break; |
583 | case R_ARM_THM_JUMP11: |
584 | // We do a 12 bit check because val is right-shifted by 1 bit. |
585 | checkInt(loc, v: val, n: 12, rel); |
586 | write16(p: loc, v: (read32(p: loc) & 0xf800) | ((val >> 1) & 0x07ff)); |
587 | break; |
588 | case R_ARM_THM_JUMP19: |
589 | // Encoding T3: Val = S:J2:J1:imm6:imm11:0 |
590 | checkInt(loc, v: val, n: 21, rel); |
591 | write16(p: loc, |
592 | v: (read16(p: loc) & 0xfbc0) | // opcode cond |
593 | ((val >> 10) & 0x0400) | // S |
594 | ((val >> 12) & 0x003f)); // imm6 |
595 | write16(p: loc + 2, |
596 | v: 0x8000 | // opcode |
597 | ((val >> 8) & 0x0800) | // J2 |
598 | ((val >> 5) & 0x2000) | // J1 |
599 | ((val >> 1) & 0x07ff)); // imm11 |
600 | break; |
601 | case R_ARM_THM_CALL: { |
602 | // R_ARM_THM_CALL is used for BL and BLX instructions, for symbols of type |
603 | // STT_FUNC we choose whether to write a BL or BLX depending on the |
604 | // value of bit 0 of Val. With bit 0 == 0 denoting ARM, if the symbol is |
605 | // not of type STT_FUNC then we must preserve the original instruction. |
606 | // PLT entries are always ARM state so we know we need to interwork. |
607 | assert(rel.sym); // R_ARM_THM_CALL is always reached via relocate(). |
608 | bool bit0Thumb = val & 1; |
609 | bool isBlx = (read16(p: loc + 2) & 0x1000) == 0; |
610 | // lld 10.0 and before always used bit0Thumb when deciding to write a BLX |
611 | // even when type not STT_FUNC. PLT entries generated by LLD are always ARM. |
612 | if (!rel.sym->isFunc() && !rel.sym->isInPlt() && isBlx == bit0Thumb) |
613 | stateChangeWarning(loc, relt: rel.type, s: *rel.sym); |
614 | if (rel.sym->isFunc() || rel.sym->isInPlt() ? !bit0Thumb : isBlx) { |
615 | // We are writing a BLX. Ensure BLX destination is 4-byte aligned. As |
616 | // the BLX instruction may only be two byte aligned. This must be done |
617 | // before overflow check. |
618 | val = alignTo(Value: val, Align: 4); |
619 | write16(p: loc + 2, v: read16(p: loc + 2) & ~0x1000); |
620 | } else { |
621 | write16(p: loc + 2, v: (read16(p: loc + 2) & ~0x1000) | 1 << 12); |
622 | } |
623 | if (!config->armJ1J2BranchEncoding) { |
624 | // Older Arm architectures do not support R_ARM_THM_JUMP24 and have |
625 | // different encoding rules and range due to J1 and J2 always being 1. |
626 | checkInt(loc, v: val, n: 23, rel); |
627 | write16(p: loc, |
628 | v: 0xf000 | // opcode |
629 | ((val >> 12) & 0x07ff)); // imm11 |
630 | write16(p: loc + 2, |
631 | v: (read16(p: loc + 2) & 0xd000) | // opcode |
632 | 0x2800 | // J1 == J2 == 1 |
633 | ((val >> 1) & 0x07ff)); // imm11 |
634 | break; |
635 | } |
636 | } |
637 | // Fall through as rest of encoding is the same as B.W |
638 | [[fallthrough]]; |
639 | case R_ARM_THM_JUMP24: |
640 | // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 |
641 | checkInt(loc, v: val, n: 25, rel); |
642 | write16(p: loc, |
643 | v: 0xf000 | // opcode |
644 | ((val >> 14) & 0x0400) | // S |
645 | ((val >> 12) & 0x03ff)); // imm10 |
646 | write16(p: loc + 2, |
647 | v: (read16(p: loc + 2) & 0xd000) | // opcode |
648 | (((~(val >> 10)) ^ (val >> 11)) & 0x2000) | // J1 |
649 | (((~(val >> 11)) ^ (val >> 13)) & 0x0800) | // J2 |
650 | ((val >> 1) & 0x07ff)); // imm11 |
651 | break; |
652 | case R_ARM_MOVW_ABS_NC: |
653 | case R_ARM_MOVW_PREL_NC: |
654 | case R_ARM_MOVW_BREL_NC: |
655 | write32(p: loc, v: (read32(p: loc) & ~0x000f0fff) | ((val & 0xf000) << 4) | |
656 | (val & 0x0fff)); |
657 | break; |
658 | case R_ARM_MOVT_ABS: |
659 | case R_ARM_MOVT_PREL: |
660 | case R_ARM_MOVT_BREL: |
661 | write32(p: loc, v: (read32(p: loc) & ~0x000f0fff) | |
662 | (((val >> 16) & 0xf000) << 4) | ((val >> 16) & 0xfff)); |
663 | break; |
664 | case R_ARM_THM_MOVT_ABS: |
665 | case R_ARM_THM_MOVT_PREL: |
666 | case R_ARM_THM_MOVT_BREL: |
667 | // Encoding T1: A = imm4:i:imm3:imm8 |
668 | |
669 | write16(p: loc, |
670 | v: 0xf2c0 | // opcode |
671 | ((val >> 17) & 0x0400) | // i |
672 | ((val >> 28) & 0x000f)); // imm4 |
673 | |
674 | write16(p: loc + 2, |
675 | v: (read16(p: loc + 2) & 0x8f00) | // opcode |
676 | ((val >> 12) & 0x7000) | // imm3 |
677 | ((val >> 16) & 0x00ff)); // imm8 |
678 | break; |
679 | case R_ARM_THM_MOVW_ABS_NC: |
680 | case R_ARM_THM_MOVW_PREL_NC: |
681 | case R_ARM_THM_MOVW_BREL_NC: |
682 | // Encoding T3: A = imm4:i:imm3:imm8 |
683 | write16(p: loc, |
684 | v: 0xf240 | // opcode |
685 | ((val >> 1) & 0x0400) | // i |
686 | ((val >> 12) & 0x000f)); // imm4 |
687 | write16(p: loc + 2, |
688 | v: (read16(p: loc + 2) & 0x8f00) | // opcode |
689 | ((val << 4) & 0x7000) | // imm3 |
690 | (val & 0x00ff)); // imm8 |
691 | break; |
692 | case R_ARM_THM_ALU_ABS_G3: |
693 | write16(p: loc, v: (read16(p: loc) &~ 0x00ff) | ((val >> 24) & 0x00ff)); |
694 | break; |
695 | case R_ARM_THM_ALU_ABS_G2_NC: |
696 | write16(p: loc, v: (read16(p: loc) &~ 0x00ff) | ((val >> 16) & 0x00ff)); |
697 | break; |
698 | case R_ARM_THM_ALU_ABS_G1_NC: |
699 | write16(p: loc, v: (read16(p: loc) &~ 0x00ff) | ((val >> 8) & 0x00ff)); |
700 | break; |
701 | case R_ARM_THM_ALU_ABS_G0_NC: |
702 | write16(p: loc, v: (read16(p: loc) &~ 0x00ff) | (val & 0x00ff)); |
703 | break; |
704 | case R_ARM_ALU_PC_G0: |
705 | encodeAluGroup(loc, rel, val, group: 0, check: true); |
706 | break; |
707 | case R_ARM_ALU_PC_G0_NC: |
708 | encodeAluGroup(loc, rel, val, group: 0, check: false); |
709 | break; |
710 | case R_ARM_ALU_PC_G1: |
711 | encodeAluGroup(loc, rel, val, group: 1, check: true); |
712 | break; |
713 | case R_ARM_ALU_PC_G1_NC: |
714 | encodeAluGroup(loc, rel, val, group: 1, check: false); |
715 | break; |
716 | case R_ARM_ALU_PC_G2: |
717 | encodeAluGroup(loc, rel, val, group: 2, check: true); |
718 | break; |
719 | case R_ARM_LDR_PC_G0: |
720 | encodeLdrGroup(loc, rel, val, group: 0); |
721 | break; |
722 | case R_ARM_LDR_PC_G1: |
723 | encodeLdrGroup(loc, rel, val, group: 1); |
724 | break; |
725 | case R_ARM_LDR_PC_G2: |
726 | encodeLdrGroup(loc, rel, val, group: 2); |
727 | break; |
728 | case R_ARM_LDRS_PC_G0: |
729 | encodeLdrsGroup(loc, rel, val, group: 0); |
730 | break; |
731 | case R_ARM_LDRS_PC_G1: |
732 | encodeLdrsGroup(loc, rel, val, group: 1); |
733 | break; |
734 | case R_ARM_LDRS_PC_G2: |
735 | encodeLdrsGroup(loc, rel, val, group: 2); |
736 | break; |
737 | case R_ARM_THM_ALU_PREL_11_0: { |
738 | // ADR encoding T2 (sub), T3 (add) i:imm3:imm8 |
739 | int64_t imm = val; |
740 | uint16_t sub = 0; |
741 | if (imm < 0) { |
742 | imm = -imm; |
743 | sub = 0x00a0; |
744 | } |
745 | checkUInt(loc, v: imm, n: 12, rel); |
746 | write16(p: loc, v: (read16(p: loc) & 0xfb0f) | sub | (imm & 0x800) >> 1); |
747 | write16(p: loc + 2, |
748 | v: (read16(p: loc + 2) & 0x8f00) | (imm & 0x700) << 4 | (imm & 0xff)); |
749 | break; |
750 | } |
751 | case R_ARM_THM_PC8: |
752 | // ADR and LDR literal encoding T1 positive offset only imm8:00 |
753 | // R_ARM_THM_PC8 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a |
754 | // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear |
755 | // bottom bit to recover S + A - Pa. |
756 | if (rel.sym->isFunc()) |
757 | val &= ~0x1; |
758 | checkUInt(loc, v: val, n: 10, rel); |
759 | checkAlignment(loc, v: val, n: 4, rel); |
760 | write16(p: loc, v: (read16(p: loc) & 0xff00) | (val & 0x3fc) >> 2); |
761 | break; |
762 | case R_ARM_THM_PC12: { |
763 | // LDR (literal) encoding T2, add = (U == '1') imm12 |
764 | // imm12 is unsigned |
765 | // R_ARM_THM_PC12 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a |
766 | // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear |
767 | // bottom bit to recover S + A - Pa. |
768 | if (rel.sym->isFunc()) |
769 | val &= ~0x1; |
770 | int64_t imm12 = val; |
771 | uint16_t u = 0x0080; |
772 | if (imm12 < 0) { |
773 | imm12 = -imm12; |
774 | u = 0; |
775 | } |
776 | checkUInt(loc, v: imm12, n: 12, rel); |
777 | write16(p: loc, v: read16(p: loc) | u); |
778 | write16(p: loc + 2, v: (read16(p: loc + 2) & 0xf000) | imm12); |
779 | break; |
780 | } |
781 | default: |
782 | llvm_unreachable("unknown relocation" ); |
783 | } |
784 | } |
785 | |
786 | int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { |
787 | switch (type) { |
788 | default: |
789 | internalLinkerError(loc: getErrorLocation(loc: buf), |
790 | msg: "cannot read addend for relocation " + toString(type)); |
791 | return 0; |
792 | case R_ARM_ABS32: |
793 | case R_ARM_BASE_PREL: |
794 | case R_ARM_GLOB_DAT: |
795 | case R_ARM_GOTOFF32: |
796 | case R_ARM_GOT_BREL: |
797 | case R_ARM_GOT_PREL: |
798 | case R_ARM_IRELATIVE: |
799 | case R_ARM_REL32: |
800 | case R_ARM_RELATIVE: |
801 | case R_ARM_SBREL32: |
802 | case R_ARM_TARGET1: |
803 | case R_ARM_TARGET2: |
804 | case R_ARM_TLS_DTPMOD32: |
805 | case R_ARM_TLS_DTPOFF32: |
806 | case R_ARM_TLS_GD32: |
807 | case R_ARM_TLS_IE32: |
808 | case R_ARM_TLS_LDM32: |
809 | case R_ARM_TLS_LE32: |
810 | case R_ARM_TLS_LDO32: |
811 | case R_ARM_TLS_TPOFF32: |
812 | return SignExtend64<32>(x: read32(p: buf)); |
813 | case R_ARM_PREL31: |
814 | return SignExtend64<31>(x: read32(p: buf)); |
815 | case R_ARM_CALL: |
816 | case R_ARM_JUMP24: |
817 | case R_ARM_PC24: |
818 | case R_ARM_PLT32: |
819 | return SignExtend64<26>(x: read32(p: buf) << 2); |
820 | case R_ARM_THM_JUMP8: |
821 | return SignExtend64<9>(x: read16(p: buf) << 1); |
822 | case R_ARM_THM_JUMP11: |
823 | return SignExtend64<12>(x: read16(p: buf) << 1); |
824 | case R_ARM_THM_JUMP19: { |
825 | // Encoding T3: A = S:J2:J1:imm10:imm6:0 |
826 | uint16_t hi = read16(p: buf); |
827 | uint16_t lo = read16(p: buf + 2); |
828 | return SignExtend64<20>(x: ((hi & 0x0400) << 10) | // S |
829 | ((lo & 0x0800) << 8) | // J2 |
830 | ((lo & 0x2000) << 5) | // J1 |
831 | ((hi & 0x003f) << 12) | // imm6 |
832 | ((lo & 0x07ff) << 1)); // imm11:0 |
833 | } |
834 | case R_ARM_THM_CALL: |
835 | if (!config->armJ1J2BranchEncoding) { |
836 | // Older Arm architectures do not support R_ARM_THM_JUMP24 and have |
837 | // different encoding rules and range due to J1 and J2 always being 1. |
838 | uint16_t hi = read16(p: buf); |
839 | uint16_t lo = read16(p: buf + 2); |
840 | return SignExtend64<22>(x: ((hi & 0x7ff) << 12) | // imm11 |
841 | ((lo & 0x7ff) << 1)); // imm11:0 |
842 | break; |
843 | } |
844 | [[fallthrough]]; |
845 | case R_ARM_THM_JUMP24: { |
846 | // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 |
847 | // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) |
848 | uint16_t hi = read16(p: buf); |
849 | uint16_t lo = read16(p: buf + 2); |
850 | return SignExtend64<24>(x: ((hi & 0x0400) << 14) | // S |
851 | (~((lo ^ (hi << 3)) << 10) & 0x00800000) | // I1 |
852 | (~((lo ^ (hi << 1)) << 11) & 0x00400000) | // I2 |
853 | ((hi & 0x003ff) << 12) | // imm0 |
854 | ((lo & 0x007ff) << 1)); // imm11:0 |
855 | } |
856 | // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and |
857 | // MOVT is in the range -32768 <= A < 32768 |
858 | case R_ARM_MOVW_ABS_NC: |
859 | case R_ARM_MOVT_ABS: |
860 | case R_ARM_MOVW_PREL_NC: |
861 | case R_ARM_MOVT_PREL: |
862 | case R_ARM_MOVW_BREL_NC: |
863 | case R_ARM_MOVT_BREL: { |
864 | uint64_t val = read32(p: buf) & 0x000f0fff; |
865 | return SignExtend64<16>(x: ((val & 0x000f0000) >> 4) | (val & 0x00fff)); |
866 | } |
867 | case R_ARM_THM_MOVW_ABS_NC: |
868 | case R_ARM_THM_MOVT_ABS: |
869 | case R_ARM_THM_MOVW_PREL_NC: |
870 | case R_ARM_THM_MOVT_PREL: |
871 | case R_ARM_THM_MOVW_BREL_NC: |
872 | case R_ARM_THM_MOVT_BREL: { |
873 | // Encoding T3: A = imm4:i:imm3:imm8 |
874 | uint16_t hi = read16(p: buf); |
875 | uint16_t lo = read16(p: buf + 2); |
876 | return SignExtend64<16>(x: ((hi & 0x000f) << 12) | // imm4 |
877 | ((hi & 0x0400) << 1) | // i |
878 | ((lo & 0x7000) >> 4) | // imm3 |
879 | (lo & 0x00ff)); // imm8 |
880 | } |
881 | case R_ARM_THM_ALU_ABS_G0_NC: |
882 | case R_ARM_THM_ALU_ABS_G1_NC: |
883 | case R_ARM_THM_ALU_ABS_G2_NC: |
884 | case R_ARM_THM_ALU_ABS_G3: |
885 | return read16(p: buf) & 0xff; |
886 | case R_ARM_ALU_PC_G0: |
887 | case R_ARM_ALU_PC_G0_NC: |
888 | case R_ARM_ALU_PC_G1: |
889 | case R_ARM_ALU_PC_G1_NC: |
890 | case R_ARM_ALU_PC_G2: { |
891 | // 12-bit immediate is a modified immediate made up of a 4-bit even |
892 | // right rotation and 8-bit constant. After the rotation the value |
893 | // is zero-extended. When bit 23 is set the instruction is an add, when |
894 | // bit 22 is set it is a sub. |
895 | uint32_t instr = read32(p: buf); |
896 | uint32_t val = rotr32(val: instr & 0xff, amt: ((instr & 0xf00) >> 8) * 2); |
897 | return (instr & 0x00400000) ? -val : val; |
898 | } |
899 | case R_ARM_LDR_PC_G0: |
900 | case R_ARM_LDR_PC_G1: |
901 | case R_ARM_LDR_PC_G2: { |
902 | // ADR (literal) add = bit23, sub = bit22 |
903 | // LDR (literal) u = bit23 unsigned imm12 |
904 | bool u = read32(p: buf) & 0x00800000; |
905 | uint32_t imm12 = read32(p: buf) & 0xfff; |
906 | return u ? imm12 : -imm12; |
907 | } |
908 | case R_ARM_LDRS_PC_G0: |
909 | case R_ARM_LDRS_PC_G1: |
910 | case R_ARM_LDRS_PC_G2: { |
911 | // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23 unsigned imm8 |
912 | uint32_t opcode = read32(p: buf); |
913 | bool u = opcode & 0x00800000; |
914 | uint32_t imm4l = opcode & 0xf; |
915 | uint32_t imm4h = (opcode & 0xf00) >> 4; |
916 | return u ? (imm4h | imm4l) : -(imm4h | imm4l); |
917 | } |
918 | case R_ARM_THM_ALU_PREL_11_0: { |
919 | // Thumb2 ADR, which is an alias for a sub or add instruction with an |
920 | // unsigned immediate. |
921 | // ADR encoding T2 (sub), T3 (add) i:imm3:imm8 |
922 | uint16_t hi = read16(p: buf); |
923 | uint16_t lo = read16(p: buf + 2); |
924 | uint64_t imm = (hi & 0x0400) << 1 | // i |
925 | (lo & 0x7000) >> 4 | // imm3 |
926 | (lo & 0x00ff); // imm8 |
927 | // For sub, addend is negative, add is positive. |
928 | return (hi & 0x00f0) ? -imm : imm; |
929 | } |
930 | case R_ARM_THM_PC8: |
931 | // ADR and LDR (literal) encoding T1 |
932 | // From ELF for the ARM Architecture the initial signed addend is formed |
933 | // from an unsigned field using expression (((imm8:00 + 4) & 0x3ff) ā 4) |
934 | // this trick permits the PC bias of -4 to be encoded using imm8 = 0xff |
935 | return ((((read16(p: buf) & 0xff) << 2) + 4) & 0x3ff) - 4; |
936 | case R_ARM_THM_PC12: { |
937 | // LDR (literal) encoding T2, add = (U == '1') imm12 |
938 | bool u = read16(p: buf) & 0x0080; |
939 | uint64_t imm12 = read16(p: buf + 2) & 0x0fff; |
940 | return u ? imm12 : -imm12; |
941 | } |
942 | case R_ARM_NONE: |
943 | case R_ARM_V4BX: |
944 | case R_ARM_JUMP_SLOT: |
945 | // These relocations are defined as not having an implicit addend. |
946 | return 0; |
947 | } |
948 | } |
949 | |
950 | static bool isArmMapSymbol(const Symbol *b) { |
951 | return b->getName() == "$a" || b->getName().starts_with(Prefix: "$a." ); |
952 | } |
953 | |
954 | static bool isThumbMapSymbol(const Symbol *s) { |
955 | return s->getName() == "$t" || s->getName().starts_with(Prefix: "$t." ); |
956 | } |
957 | |
958 | static bool isDataMapSymbol(const Symbol *b) { |
959 | return b->getName() == "$d" || b->getName().starts_with(Prefix: "$d." ); |
960 | } |
961 | |
962 | void elf::sortArmMappingSymbols() { |
963 | // For each input section make sure the mapping symbols are sorted in |
964 | // ascending order. |
965 | for (auto &kv : sectionMap) { |
966 | SmallVector<const Defined *, 0> &mapSyms = kv.second; |
967 | llvm::stable_sort(Range&: mapSyms, C: [](const Defined *a, const Defined *b) { |
968 | return a->value < b->value; |
969 | }); |
970 | } |
971 | } |
972 | |
973 | void elf::addArmInputSectionMappingSymbols() { |
974 | // Collect mapping symbols for every executable input sections. |
975 | // The linker generated mapping symbols for all the synthetic |
976 | // sections are adding into the sectionmap through the function |
977 | // addArmSyntheitcSectionMappingSymbol. |
978 | for (ELFFileBase *file : ctx.objectFiles) { |
979 | for (Symbol *sym : file->getLocalSymbols()) { |
980 | auto *def = dyn_cast<Defined>(Val: sym); |
981 | if (!def) |
982 | continue; |
983 | if (!isArmMapSymbol(b: def) && !isDataMapSymbol(b: def) && |
984 | !isThumbMapSymbol(s: def)) |
985 | continue; |
986 | if (auto *sec = cast_if_present<InputSection>(Val: def->section)) |
987 | if (sec->flags & SHF_EXECINSTR) |
988 | sectionMap[sec].push_back(Elt: def); |
989 | } |
990 | } |
991 | } |
992 | |
993 | // Synthetic sections are not backed by an ELF file where we can access the |
994 | // symbol table, instead mapping symbols added to synthetic sections are stored |
995 | // in the synthetic symbol table. Due to the presence of strip (--strip-all), |
996 | // we can not rely on the synthetic symbol table retaining the mapping symbols. |
997 | // Instead we record the mapping symbols locally. |
998 | void elf::addArmSyntheticSectionMappingSymbol(Defined *sym) { |
999 | if (!isArmMapSymbol(b: sym) && !isDataMapSymbol(b: sym) && !isThumbMapSymbol(s: sym)) |
1000 | return; |
1001 | if (auto *sec = cast_if_present<InputSection>(Val: sym->section)) |
1002 | if (sec->flags & SHF_EXECINSTR) |
1003 | sectionMap[sec].push_back(Elt: sym); |
1004 | } |
1005 | |
1006 | static void toLittleEndianInstructions(uint8_t *buf, uint64_t start, |
1007 | uint64_t end, uint64_t width) { |
1008 | CodeState curState = static_cast<CodeState>(width); |
1009 | if (curState == CodeState::Arm) |
1010 | for (uint64_t i = start; i < end; i += width) |
1011 | write32le(P: buf + i, V: read32(p: buf + i)); |
1012 | |
1013 | if (curState == CodeState::Thumb) |
1014 | for (uint64_t i = start; i < end; i += width) |
1015 | write16le(P: buf + i, V: read16(p: buf + i)); |
1016 | } |
1017 | |
1018 | // Arm BE8 big endian format requires instructions to be little endian, with |
1019 | // the initial contents big-endian. Convert the big-endian instructions to |
1020 | // little endian leaving literal data untouched. We use mapping symbols to |
1021 | // identify half open intervals of Arm code [$a, non $a) and Thumb code |
1022 | // [$t, non $t) and convert these to little endian a word or half word at a |
1023 | // time respectively. |
1024 | void elf::convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf) { |
1025 | if (!sectionMap.contains(Val: sec)) |
1026 | return; |
1027 | |
1028 | SmallVector<const Defined *, 0> &mapSyms = sectionMap[sec]; |
1029 | |
1030 | if (mapSyms.empty()) |
1031 | return; |
1032 | |
1033 | CodeState curState = CodeState::Data; |
1034 | uint64_t start = 0, width = 0, size = sec->getSize(); |
1035 | for (auto &msym : mapSyms) { |
1036 | CodeState newState = CodeState::Data; |
1037 | if (isThumbMapSymbol(s: msym)) |
1038 | newState = CodeState::Thumb; |
1039 | else if (isArmMapSymbol(b: msym)) |
1040 | newState = CodeState::Arm; |
1041 | |
1042 | if (newState == curState) |
1043 | continue; |
1044 | |
1045 | if (curState != CodeState::Data) { |
1046 | width = static_cast<uint64_t>(curState); |
1047 | toLittleEndianInstructions(buf, start, end: msym->value, width); |
1048 | } |
1049 | start = msym->value; |
1050 | curState = newState; |
1051 | } |
1052 | |
1053 | // Passed last mapping symbol, may need to reverse |
1054 | // up to end of section. |
1055 | if (curState != CodeState::Data) { |
1056 | width = static_cast<uint64_t>(curState); |
1057 | toLittleEndianInstructions(buf, start, end: size, width); |
1058 | } |
1059 | } |
1060 | |
1061 | // The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts; |
1062 | // the non-secure and secure states with the secure state inaccessible from the |
1063 | // non-secure state, apart from an area of memory in secure state called the |
1064 | // secure gateway which is accessible from non-secure state. The secure gateway |
1065 | // contains one or more entry points which must start with a landing pad |
1066 | // instruction SG. Arm recommends that the secure gateway consists only of |
1067 | // secure gateway veneers, which are made up of a SG instruction followed by a |
1068 | // branch to the destination in secure state. Full details can be found in Arm |
1069 | // v8-M Security Extensions Requirements on Development Tools. |
1070 | // |
1071 | // The CMSE model of software development requires the non-secure and secure |
1072 | // states to be developed as two separate programs. The non-secure developer is |
1073 | // provided with an import library defining symbols describing the entry points |
1074 | // in the secure gateway. No additional linker support is required for the |
1075 | // non-secure state. |
1076 | // |
1077 | // Development of the secure state requires linker support to manage the secure |
1078 | // gateway veneers. The management consists of: |
1079 | // - Creation of new secure gateway veneers based on symbol conventions. |
1080 | // - Checking the address of existing secure gateway veneers. |
1081 | // - Warning when existing secure gateway veneers removed. |
1082 | // |
1083 | // The secure gateway veneers are created in an import library, which is just an |
1084 | // ELF object with a symbol table. The import library is controlled by two |
1085 | // command line options: |
1086 | // --in-implib (specify an input import library from a previous revision of the |
1087 | // program). |
1088 | // --out-implib (specify an output import library to be created by the linker). |
1089 | // |
1090 | // The input import library is used to manage consistency of the secure entry |
1091 | // points. The output import library is for new and updated secure entry points. |
1092 | // |
1093 | // The symbol convention that identifies secure entry functions is the prefix |
1094 | // __acle_se_ for a symbol called name the linker is expected to create a secure |
1095 | // gateway veneer if symbols __acle_se_name and name have the same address. |
1096 | // After creating a secure gateway veneer the symbol name labels the secure |
1097 | // gateway veneer and the __acle_se_name labels the function definition. |
1098 | // |
1099 | // The LLD implementation: |
1100 | // - Reads an existing import library with importCmseSymbols(). |
1101 | // - Determines which new secure gateway veneers to create and redirects calls |
1102 | // within the secure state to the __acle_se_ prefixed symbol with |
1103 | // processArmCmseSymbols(). |
1104 | // - Models the SG veneers as a synthetic section. |
1105 | |
1106 | // Initialize symbols. symbols is a parallel array to the corresponding ELF |
1107 | // symbol table. |
1108 | template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() { |
1109 | ArrayRef<Elf_Sym> eSyms = getELFSyms<ELFT>(); |
1110 | // Error for local symbols. The symbol at index 0 is LOCAL. So skip it. |
1111 | for (size_t i = 1, end = firstGlobal; i != end; ++i) { |
1112 | errorOrWarn("CMSE symbol '" + CHECK(eSyms[i].getName(stringTable), this) + |
1113 | "' in import library '" + toString(this) + "' is not global" ); |
1114 | } |
1115 | |
1116 | for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) { |
1117 | const Elf_Sym &eSym = eSyms[i]; |
1118 | Defined *sym = reinterpret_cast<Defined *>(make<SymbolUnion>()); |
1119 | |
1120 | // Initialize symbol fields. |
1121 | memset(s: sym, c: 0, n: sizeof(Symbol)); |
1122 | sym->setName(CHECK(eSyms[i].getName(stringTable), this)); |
1123 | sym->value = eSym.st_value; |
1124 | sym->size = eSym.st_size; |
1125 | sym->type = eSym.getType(); |
1126 | sym->binding = eSym.getBinding(); |
1127 | sym->stOther = eSym.st_other; |
1128 | |
1129 | if (eSym.st_shndx != SHN_ABS) { |
1130 | error("CMSE symbol '" + sym->getName() + "' in import library '" + |
1131 | toString(this) + "' is not absolute" ); |
1132 | continue; |
1133 | } |
1134 | |
1135 | if (!(eSym.st_value & 1) || (eSym.getType() != STT_FUNC)) { |
1136 | error("CMSE symbol '" + sym->getName() + "' in import library '" + |
1137 | toString(this) + "' is not a Thumb function definition" ); |
1138 | continue; |
1139 | } |
1140 | |
1141 | if (symtab.cmseImportLib.count(Key: sym->getName())) { |
1142 | error("CMSE symbol '" + sym->getName() + |
1143 | "' is multiply defined in import library '" + toString(this) + "'" ); |
1144 | continue; |
1145 | } |
1146 | |
1147 | if (eSym.st_size != ACLESESYM_SIZE) { |
1148 | warn("CMSE symbol '" + sym->getName() + "' in import library '" + |
1149 | toString(this) + "' does not have correct size of " + |
1150 | Twine(ACLESESYM_SIZE) + " bytes" ); |
1151 | } |
1152 | |
1153 | symtab.cmseImportLib[sym->getName()] = sym; |
1154 | } |
1155 | } |
1156 | |
1157 | // Check symbol attributes of the acleSeSym, sym pair. |
1158 | // Both symbols should be global/weak Thumb code symbol definitions. |
1159 | static std::string checkCmseSymAttributes(Symbol *acleSeSym, Symbol *sym) { |
1160 | auto check = [](Symbol *s, StringRef type) -> std::optional<std::string> { |
1161 | auto d = dyn_cast_or_null<Defined>(Val: s); |
1162 | if (!(d && d->isFunc() && (d->value & 1))) |
1163 | return (Twine(toString(f: s->file)) + ": cmse " + type + " symbol '" + |
1164 | s->getName() + "' is not a Thumb function definition" ) |
1165 | .str(); |
1166 | if (!d->section) |
1167 | return (Twine(toString(f: s->file)) + ": cmse " + type + " symbol '" + |
1168 | s->getName() + "' cannot be an absolute symbol" ) |
1169 | .str(); |
1170 | return std::nullopt; |
1171 | }; |
1172 | for (auto [sym, type] : |
1173 | {std::make_pair(x&: acleSeSym, y: "special" ), std::make_pair(x&: sym, y: "entry" )}) |
1174 | if (auto err = check(sym, type)) |
1175 | return *err; |
1176 | return "" ; |
1177 | } |
1178 | |
1179 | // Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M |
1180 | // Security Extensions specification. |
1181 | // 1) <sym> : A standard function name. |
1182 | // 2) __acle_se_<sym> : A special symbol that prefixes the standard function |
1183 | // name with __acle_se_. |
1184 | // Both these symbols are Thumb function symbols with external linkage. |
1185 | // <sym> may be redefined in .gnu.sgstubs. |
1186 | void elf::processArmCmseSymbols() { |
1187 | if (!config->cmseImplib) |
1188 | return; |
1189 | // Only symbols with external linkage end up in symtab, so no need to do |
1190 | // linkage checks. Only check symbol type. |
1191 | for (Symbol *acleSeSym : symtab.getSymbols()) { |
1192 | if (!acleSeSym->getName().starts_with(Prefix: ACLESESYM_PREFIX)) |
1193 | continue; |
1194 | // If input object build attributes do not support CMSE, error and disable |
1195 | // further scanning for <sym>, __acle_se_<sym> pairs. |
1196 | if (!config->armCMSESupport) { |
1197 | error(msg: "CMSE is only supported by ARMv8-M architecture or later" ); |
1198 | config->cmseImplib = false; |
1199 | break; |
1200 | } |
1201 | |
1202 | // Try to find the associated symbol definition. |
1203 | // Symbol must have external linkage. |
1204 | StringRef name = acleSeSym->getName().substr(Start: std::strlen(s: ACLESESYM_PREFIX)); |
1205 | Symbol *sym = symtab.find(name); |
1206 | if (!sym) { |
1207 | error(msg: toString(f: acleSeSym->file) + ": cmse special symbol '" + |
1208 | acleSeSym->getName() + |
1209 | "' detected, but no associated entry function definition '" + name + |
1210 | "' with external linkage found" ); |
1211 | continue; |
1212 | } |
1213 | |
1214 | std::string errMsg = checkCmseSymAttributes(acleSeSym, sym); |
1215 | if (!errMsg.empty()) { |
1216 | error(msg: errMsg); |
1217 | continue; |
1218 | } |
1219 | |
1220 | // <sym> may be redefined later in the link in .gnu.sgstubs |
1221 | symtab.cmseSymMap[name] = {.acleSeSym: acleSeSym, .sym: sym}; |
1222 | } |
1223 | |
1224 | // If this is an Arm CMSE secure app, replace references to entry symbol <sym> |
1225 | // with its corresponding special symbol __acle_se_<sym>. |
1226 | parallelForEach(R&: ctx.objectFiles, Fn: [&](InputFile *file) { |
1227 | MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); |
1228 | for (size_t i = 0, e = syms.size(); i != e; ++i) { |
1229 | StringRef symName = syms[i]->getName(); |
1230 | if (symtab.cmseSymMap.count(Key: symName)) |
1231 | syms[i] = symtab.cmseSymMap[symName].acleSeSym; |
1232 | } |
1233 | }); |
1234 | } |
1235 | |
1236 | class elf::ArmCmseSGVeneer { |
1237 | public: |
1238 | ArmCmseSGVeneer(Symbol *sym, Symbol *acleSeSym, |
1239 | std::optional<uint64_t> addr = std::nullopt) |
1240 | : sym(sym), acleSeSym(acleSeSym), entAddr{addr} {} |
1241 | static const size_t size{ACLESESYM_SIZE}; |
1242 | const std::optional<uint64_t> getAddr() const { return entAddr; }; |
1243 | |
1244 | Symbol *sym; |
1245 | Symbol *acleSeSym; |
1246 | uint64_t offset = 0; |
1247 | |
1248 | private: |
1249 | const std::optional<uint64_t> entAddr; |
1250 | }; |
1251 | |
1252 | ArmCmseSGSection::ArmCmseSGSection() |
1253 | : SyntheticSection(llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR, |
1254 | llvm::ELF::SHT_PROGBITS, |
1255 | /*alignment=*/32, ".gnu.sgstubs" ) { |
1256 | entsize = ACLESESYM_SIZE; |
1257 | // The range of addresses used in the CMSE import library should be fixed. |
1258 | for (auto &[_, sym] : symtab.cmseImportLib) { |
1259 | if (impLibMaxAddr <= sym->value) |
1260 | impLibMaxAddr = sym->value + sym->size; |
1261 | } |
1262 | if (symtab.cmseSymMap.empty()) |
1263 | return; |
1264 | addMappingSymbol(); |
1265 | for (auto &[_, entryFunc] : symtab.cmseSymMap) |
1266 | addSGVeneer(sym: cast<Defined>(Val: entryFunc.acleSeSym), |
1267 | ext_sym: cast<Defined>(Val: entryFunc.sym)); |
1268 | for (auto &[_, sym] : symtab.cmseImportLib) { |
1269 | if (!symtab.inCMSEOutImpLib.count(Key: sym->getName())) |
1270 | warn(msg: "entry function '" + sym->getName() + |
1271 | "' from CMSE import library is not present in secure application" ); |
1272 | } |
1273 | |
1274 | if (!symtab.cmseImportLib.empty() && config->cmseOutputLib.empty()) { |
1275 | for (auto &[_, entryFunc] : symtab.cmseSymMap) { |
1276 | Symbol *sym = entryFunc.sym; |
1277 | if (!symtab.inCMSEOutImpLib.count(Key: sym->getName())) |
1278 | warn(msg: "new entry function '" + sym->getName() + |
1279 | "' introduced but no output import library specified" ); |
1280 | } |
1281 | } |
1282 | } |
1283 | |
1284 | void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) { |
1285 | entries.emplace_back(Args&: acleSeSym, Args&: sym); |
1286 | if (symtab.cmseImportLib.count(Key: sym->getName())) |
1287 | symtab.inCMSEOutImpLib[sym->getName()] = true; |
1288 | // Symbol addresses different, nothing to do. |
1289 | if (acleSeSym->file != sym->file || |
1290 | cast<Defined>(Val&: *acleSeSym).value != cast<Defined>(Val&: *sym).value) |
1291 | return; |
1292 | // Only secure symbols with values equal to that of it's non-secure |
1293 | // counterpart needs to be in the .gnu.sgstubs section. |
1294 | ArmCmseSGVeneer *ss = nullptr; |
1295 | if (symtab.cmseImportLib.count(Key: sym->getName())) { |
1296 | Defined *impSym = symtab.cmseImportLib[sym->getName()]; |
1297 | ss = make<ArmCmseSGVeneer>(args&: sym, args&: acleSeSym, args&: impSym->value); |
1298 | } else { |
1299 | ss = make<ArmCmseSGVeneer>(args&: sym, args&: acleSeSym); |
1300 | ++newEntries; |
1301 | } |
1302 | sgVeneers.emplace_back(Args&: ss); |
1303 | } |
1304 | |
1305 | void ArmCmseSGSection::writeTo(uint8_t *buf) { |
1306 | for (ArmCmseSGVeneer *s : sgVeneers) { |
1307 | uint8_t *p = buf + s->offset; |
1308 | write16(p: p + 0, v: 0xe97f); // SG |
1309 | write16(p: p + 2, v: 0xe97f); |
1310 | write16(p: p + 4, v: 0xf000); // B.W S |
1311 | write16(p: p + 6, v: 0xb000); |
1312 | target->relocateNoSym(loc: p + 4, type: R_ARM_THM_JUMP24, |
1313 | val: s->acleSeSym->getVA() - |
1314 | (getVA() + s->offset + s->size)); |
1315 | } |
1316 | } |
1317 | |
1318 | void ArmCmseSGSection::addMappingSymbol() { |
1319 | addSyntheticLocal(name: "$t" , type: STT_NOTYPE, /*off=*/value: 0, /*size=*/0, section&: *this); |
1320 | } |
1321 | |
1322 | size_t ArmCmseSGSection::getSize() const { |
1323 | if (sgVeneers.empty()) |
1324 | return (impLibMaxAddr ? impLibMaxAddr - getVA() : 0) + newEntries * entsize; |
1325 | |
1326 | return entries.size() * entsize; |
1327 | } |
1328 | |
1329 | void ArmCmseSGSection::finalizeContents() { |
1330 | if (sgVeneers.empty()) |
1331 | return; |
1332 | |
1333 | auto it = |
1334 | std::stable_partition(first: sgVeneers.begin(), last: sgVeneers.end(), |
1335 | pred: [](auto *i) { return i->getAddr().has_value(); }); |
1336 | std::sort(first: sgVeneers.begin(), last: it, comp: [](auto *a, auto *b) { |
1337 | return a->getAddr().value() < b->getAddr().value(); |
1338 | }); |
1339 | // This is the partition of the veneers with fixed addresses. |
1340 | uint64_t addr = (*sgVeneers.begin())->getAddr().has_value() |
1341 | ? (*sgVeneers.begin())->getAddr().value() |
1342 | : getVA(); |
1343 | // Check if the start address of '.gnu.sgstubs' correspond to the |
1344 | // linker-synthesized veneer with the lowest address. |
1345 | if ((getVA() & ~1) != (addr & ~1)) { |
1346 | error(msg: "start address of '.gnu.sgstubs' is different from previous link" ); |
1347 | return; |
1348 | } |
1349 | |
1350 | for (size_t i = 0; i < sgVeneers.size(); ++i) { |
1351 | ArmCmseSGVeneer *s = sgVeneers[i]; |
1352 | s->offset = i * s->size; |
1353 | Defined(file, StringRef(), s->sym->binding, s->sym->stOther, s->sym->type, |
1354 | s->offset | 1, s->size, this) |
1355 | .overwrite(sym&: *s->sym); |
1356 | } |
1357 | } |
1358 | |
1359 | // Write the CMSE import library to disk. |
1360 | // The CMSE import library is a relocatable object with only a symbol table. |
1361 | // The symbols are copies of the (absolute) symbols of the secure gateways |
1362 | // in the executable output by this link. |
1363 | // See ArmĀ® v8-M Security Extensions: Requirements on Development Tools |
1364 | // https://developer.arm.com/documentation/ecm0359818/latest |
1365 | template <typename ELFT> void elf::writeARMCmseImportLib() { |
1366 | StringTableSection *shstrtab = |
1367 | make<StringTableSection>(args: ".shstrtab" , /*dynamic=*/args: false); |
1368 | StringTableSection *strtab = |
1369 | make<StringTableSection>(args: ".strtab" , /*dynamic=*/args: false); |
1370 | SymbolTableBaseSection *impSymTab = make<SymbolTableSection<ELFT>>(*strtab); |
1371 | |
1372 | SmallVector<std::pair<OutputSection *, SyntheticSection *>, 0> osIsPairs; |
1373 | osIsPairs.emplace_back(Args: make<OutputSection>(args&: strtab->name, args: 0, args: 0), Args&: strtab); |
1374 | osIsPairs.emplace_back(Args: make<OutputSection>(args&: impSymTab->name, args: 0, args: 0), Args&: impSymTab); |
1375 | osIsPairs.emplace_back(Args: make<OutputSection>(args&: shstrtab->name, args: 0, args: 0), Args&: shstrtab); |
1376 | |
1377 | std::sort(symtab.cmseSymMap.begin(), symtab.cmseSymMap.end(), |
1378 | [](const auto &a, const auto &b) -> bool { |
1379 | return a.second.sym->getVA() < b.second.sym->getVA(); |
1380 | }); |
1381 | // Copy the secure gateway entry symbols to the import library symbol table. |
1382 | for (auto &p : symtab.cmseSymMap) { |
1383 | Defined *d = cast<Defined>(Val: p.second.sym); |
1384 | impSymTab->addSymbol(sym: makeDefined( |
1385 | args&: ctx.internalFile, args: d->getName(), args: d->computeBinding(), |
1386 | /*stOther=*/args: 0, args: STT_FUNC, args: d->getVA(), args: d->getSize(), args: nullptr)); |
1387 | } |
1388 | |
1389 | size_t idx = 0; |
1390 | uint64_t off = sizeof(typename ELFT::Ehdr); |
1391 | for (auto &[osec, isec] : osIsPairs) { |
1392 | osec->sectionIndex = ++idx; |
1393 | osec->recordSection(isec); |
1394 | osec->finalizeInputSections(); |
1395 | osec->shName = shstrtab->addString(s: osec->name); |
1396 | osec->size = isec->getSize(); |
1397 | isec->finalizeContents(); |
1398 | osec->offset = alignToPowerOf2(Value: off, Align: osec->addralign); |
1399 | off = osec->offset + osec->size; |
1400 | } |
1401 | |
1402 | const uint64_t = alignToPowerOf2(Value: off, Align: config->wordsize); |
1403 | const auto shnum = osIsPairs.size() + 1; |
1404 | const uint64_t fileSize = |
1405 | sectionHeaderOff + shnum * sizeof(typename ELFT::Shdr); |
1406 | const unsigned flags = |
1407 | config->mmapOutputFile ? 0 : (unsigned)FileOutputBuffer::F_no_mmap; |
1408 | unlinkAsync(path: config->cmseOutputLib); |
1409 | Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr = |
1410 | FileOutputBuffer::create(FilePath: config->cmseOutputLib, Size: fileSize, Flags: flags); |
1411 | if (!bufferOrErr) { |
1412 | error(msg: "failed to open " + config->cmseOutputLib + ": " + |
1413 | llvm::toString(E: bufferOrErr.takeError())); |
1414 | return; |
1415 | } |
1416 | |
1417 | // Write the ELF Header |
1418 | std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr; |
1419 | uint8_t *const buf = buffer->getBufferStart(); |
1420 | memcpy(dest: buf, src: "\177ELF" , n: 4); |
1421 | auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf); |
1422 | eHdr->e_type = ET_REL; |
1423 | eHdr->e_entry = 0; |
1424 | eHdr->e_shoff = sectionHeaderOff; |
1425 | eHdr->e_ident[EI_CLASS] = ELFCLASS32; |
1426 | eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; |
1427 | eHdr->e_ident[EI_VERSION] = EV_CURRENT; |
1428 | eHdr->e_ident[EI_OSABI] = config->osabi; |
1429 | eHdr->e_ident[EI_ABIVERSION] = 0; |
1430 | eHdr->e_machine = EM_ARM; |
1431 | eHdr->e_version = EV_CURRENT; |
1432 | eHdr->e_flags = config->eflags; |
1433 | eHdr->e_ehsize = sizeof(typename ELFT::Ehdr); |
1434 | eHdr->e_phnum = 0; |
1435 | eHdr->e_shentsize = sizeof(typename ELFT::Shdr); |
1436 | eHdr->e_phoff = 0; |
1437 | eHdr->e_phentsize = 0; |
1438 | eHdr->e_shnum = shnum; |
1439 | eHdr->e_shstrndx = shstrtab->getParent()->sectionIndex; |
1440 | |
1441 | // Write the section header table. |
1442 | auto *sHdrs = reinterpret_cast<typename ELFT::Shdr *>(buf + eHdr->e_shoff); |
1443 | for (auto &[osec, _] : osIsPairs) |
1444 | osec->template writeHeaderTo<ELFT>(++sHdrs); |
1445 | |
1446 | // Write section contents to a mmap'ed file. |
1447 | { |
1448 | parallel::TaskGroup tg; |
1449 | for (auto &[osec, _] : osIsPairs) |
1450 | osec->template writeTo<ELFT>(buf + osec->offset, tg); |
1451 | } |
1452 | |
1453 | if (auto e = buffer->commit()) |
1454 | fatal(msg: "failed to write output '" + buffer->getPath() + |
1455 | "': " + toString(E: std::move(e))); |
1456 | } |
1457 | |
1458 | TargetInfo *elf::getARMTargetInfo() { |
1459 | static ARM target; |
1460 | return ⌖ |
1461 | } |
1462 | |
1463 | template void elf::writeARMCmseImportLib<ELF32LE>(); |
1464 | template void elf::writeARMCmseImportLib<ELF32BE>(); |
1465 | template void elf::writeARMCmseImportLib<ELF64LE>(); |
1466 | template void elf::writeARMCmseImportLib<ELF64BE>(); |
1467 | |
1468 | template void ObjFile<ELF32LE>::importCmseSymbols(); |
1469 | template void ObjFile<ELF32BE>::importCmseSymbols(); |
1470 | template void ObjFile<ELF64LE>::importCmseSymbols(); |
1471 | template void ObjFile<ELF64BE>::importCmseSymbols(); |
1472 | |