LLVM 24.0.0git
ELF_mips.cpp
Go to the documentation of this file.
1//===-- ELF_mips.cpp - JIT linker implementation for ELF/MIPS ------------===//
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
10
11#include "EHFrameSupportImpl.h"
12#include "ELFLinkGraphBuilder.h"
13#include "JITLinkGeneric.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/STLExtras.h"
20#include "llvm/Object/ELF.h"
22#include "llvm/Support/Endian.h"
27
28#include <tuple>
29
30#define DEBUG_TYPE "jitlink"
31
32using namespace llvm;
33using namespace llvm::jitlink;
34using namespace llvm::jitlink::mips;
35
36namespace {
37
38constexpr StringRef GOTSectionName = "$__GOT";
39constexpr StringRef StubsSectionName = "$__STUBS";
40constexpr StringRef TLSInfoSectionName = "$__TLSINFO";
41constexpr StringRef TLSBaseName = "__jitlink_mips_tls_base";
42constexpr StringRef GOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
43constexpr StringRef GPName = "_gp";
44constexpr StringRef GPDispName = "_gp_disp";
45constexpr StringRef LocalGPName = "__gnu_local_gp";
46constexpr unsigned RelocationTypeBits = 8;
47constexpr unsigned MaxRelocationOperations = 3;
48constexpr int64_t CompactBranchPCBias = InstructionSize;
49// The MIPS psABI defines $gp as 0x7ff0 bytes past the GOT base.
50constexpr uint64_t GPAnchorOffset = 0x7ff0;
51
52enum class MipsABI { O32, N32, N64 };
53
54static Edge::Kind getPagePointerEdgeKind(const LinkGraph &G) {
55 return G.getPointerSize() == 8 ? PagePointer64 : PagePointer32;
56}
57
58template <unsigned Bits, unsigned Shift>
59static int64_t decodeInstructionImmediate(uint32_t Instruction) {
60 static_assert(Bits + Shift <= 32);
63}
64
65static uint8_t getPackedRelocationField(uint32_t Packed, unsigned Index) {
66 return static_cast<uint8_t>((Packed >> (Index * RelocationTypeBits)) &
67 maskTrailingOnes<uint32_t>(RelocationTypeBits));
68}
69
70static std::string getRelocationChainName(ArrayRef<uint8_t> Types) {
71 std::string Result;
72 raw_string_ostream OS(Result);
73 for (auto [Index, Type] : llvm::enumerate(Types)) {
74 if (Index)
75 OS << '/';
77 }
78 return Result;
79}
80
81static unsigned getFixupSize(Edge::Kind K) {
82 switch (K) {
83 case Abs16:
84 return sizeof(uint16_t);
85 case Pointer64:
86 case PagePointer64:
87 case Delta64:
88 case GPRel64:
89 case DTPRel64:
90 return sizeof(uint64_t);
91 case Pointer32:
92 case PagePointer32:
93 case Delta32:
94 case NegDelta32:
95 case Hi16:
96 case Lo16:
97 case Higher16:
98 case Highest16:
99 case Jump26:
100 case PC16:
101 case PC32:
102 case PC18S3:
103 case PC19S2:
104 case PC21S2:
105 case PC26S2:
106 case PCHi16:
107 case PCLo16:
108 case GPDispHi16:
109 case GPDispLo16:
110 case GPRel16:
111 case GPRel32:
112 case GOTOffset16:
113 case GOTOffsetHi16:
114 case GOTOffsetLo16:
115 case GOTPageOffset16:
116 case DTPRelHi16:
117 case DTPRelLo16:
118 case DTPRel32:
119 case NegGPRelHi16:
120 case NegGPRelLo16:
127 return sizeof(uint32_t);
128 default:
129 llvm_unreachable("not a MIPS relocation edge");
130 }
131}
132
133class ELFJITLinker_mips : public JITLinker<ELFJITLinker_mips> {
134 friend class JITLinker<ELFJITLinker_mips>;
135
136public:
137 ELFJITLinker_mips(std::unique_ptr<JITLinkContext> Ctx,
138 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
139 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
140 getPassConfig().PreFixupPasses.push_back([this](LinkGraph &G) {
141 GPSymbol = G.findDefinedSymbolByName(G.intern(GPName));
142 TLSBaseSymbol = G.findDefinedSymbolByName(G.intern(TLSBaseName));
143 return Error::success();
144 });
145 }
146
147private:
148 Symbol *GPSymbol = nullptr;
149 Symbol *TLSBaseSymbol = nullptr;
150
151 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
152 return mips::applyFixup(G, B, E, GPSymbol, TLSBaseSymbol);
153 }
154};
155
156template <typename ELFT>
157class ELFLinkGraphBuilder_mips : public ELFLinkGraphBuilder<ELFT> {
159 using Rel = typename ELFT::Rel;
160 using Rela = typename ELFT::Rela;
161
162 struct Reloc {
166 int64_t Addend;
167 };
168
169public:
170 ELFLinkGraphBuilder_mips(StringRef FileName, const object::ELFFile<ELFT> &Obj,
171 std::shared_ptr<orc::SymbolStringPool> SSP,
172 Triple TT, SubtargetFeatures Features, MipsABI ABI)
173 : Base(Obj, std::move(SSP), std::move(TT), std::move(Features), FileName,
175 ABI(ABI) {}
176
177private:
178 MipsABI ABI;
179
180 bool excludeSection(const typename ELFT::Shdr &Sec) const override {
181 return Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS ||
182 Sec.sh_type == ELF::SHT_MIPS_REGINFO ||
183 Sec.sh_type == ELF::SHT_MIPS_OPTIONS;
184 }
185
186 Error error(const typename ELFT::Shdr &FixupSect, uint64_t Offset,
187 const Twine &Message) const {
188 auto Name = Base::Obj.getSectionName(FixupSect);
189 if (!Name)
190 return Name.takeError();
191 return make_error<JITLinkError>(Base::G->getName() + ": section " + *Name +
192 "+0x" + utohexstr(Offset) + ": " + Message);
193 }
194
195 Expected<int64_t> implicitAddend(const typename ELFT::Shdr &RelSect,
196 uint8_t Type, const Block &B,
197 uint64_t Offset) const {
198 if (Type == ELF::R_MIPS_NONE || Type == ELF::R_MIPS_JALR)
199 return 0;
200
201 unsigned FixupSize = Type == ELF::R_MIPS_16 ? sizeof(uint16_t)
202 : Type == ELF::R_MIPS_64 ? sizeof(uint64_t)
203 : sizeof(uint32_t);
204 if (Offset > B.getSize() || FixupSize > B.getSize() - Offset)
205 return error(RelSect, Offset,
206 "relocation fixup extends past the end of its block");
207
208 const char *P = B.getContent().data() + Offset;
209 if (Type == ELF::R_MIPS_16)
211
212 if (Type == ELF::R_MIPS_64)
214
216 switch (Type) {
217 case ELF::R_MIPS_32:
218 case ELF::R_MIPS_GPREL32:
219 case ELF::R_MIPS_PC32:
220 case ELF::R_MIPS_TLS_DTPREL32:
221 return SignExtend64<32>(W);
222 case ELF::R_MIPS_26:
223 return decodeInstructionImmediate<26, 2>(W);
224 case ELF::R_MIPS_HI16:
225 case ELF::R_MIPS_PCHI16:
226 case ELF::R_MIPS_GOT16:
227 case ELF::R_MIPS_GOT_HI16:
228 case ELF::R_MIPS_CALL_HI16:
229 return decodeInstructionImmediate<16, 16>(W);
230 case ELF::R_MIPS_PC16:
231 return decodeInstructionImmediate<16, 2>(W);
232 case ELF::R_MIPS_PC18_S3:
233 return decodeInstructionImmediate<18, 3>(W);
234 case ELF::R_MIPS_PC19_S2:
235 return decodeInstructionImmediate<19, 2>(W);
236 case ELF::R_MIPS_PC21_S2:
237 return decodeInstructionImmediate<21, 2>(W);
238 case ELF::R_MIPS_PC26_S2:
239 return decodeInstructionImmediate<26, 2>(W);
240 default:
241 return decodeInstructionImmediate<16, 0>(W);
242 }
243 }
244
245 static uint8_t matchingLow(uint8_t Type, bool IsLocal) {
246 switch (Type) {
247 case ELF::R_MIPS_HI16:
248 return ELF::R_MIPS_LO16;
249 case ELF::R_MIPS_PCHI16:
250 return ELF::R_MIPS_PCLO16;
251 case ELF::R_MIPS_GOT16:
252 return IsLocal ? ELF::R_MIPS_LO16 : ELF::R_MIPS_NONE;
253 default:
254 return ELF::R_MIPS_NONE;
255 }
256 }
257
258 Error validateSymbols() {
259 if (!Base::SymTabSec)
260 return Error::success();
261 auto Symbols = Base::Obj.symbols(Base::SymTabSec);
262 if (!Symbols)
263 return Symbols.takeError();
264 for (const auto &Sym : *Symbols)
265 if ((Sym.st_other & ELF::STO_MIPS_MICROMIPS) ||
266 (Sym.st_other & ELF::STO_MIPS_MIPS16) == ELF::STO_MIPS_MIPS16)
268 Base::G->getName() +
269 ": compact-mode MIPS16/microMIPS symbols are unsupported");
270 return Error::success();
271 }
272
273 Error collectRelocs(const typename ELFT::Shdr &RelSect, Block &B,
275 if (RelSect.sh_type == ELF::SHT_RELA) {
276 auto Rs = Base::Obj.relas(RelSect);
277 if (!Rs)
278 return Rs.takeError();
279 for (auto I = Rs->begin(), E = Rs->end(); I != E;) {
280 const Rela &R = *I++;
281 if (ABI == MipsABI::N32) {
282 Reloc RR{R.r_offset, R.getSymbol(false), {}, R.r_addend};
283 RR.Types.push_back(R.getType(false));
284 while (I != E && I->r_offset == R.r_offset) {
285 if (RR.Types.size() == MaxRelocationOperations)
286 return error(RelSect, R.r_offset,
287 "more than three N32 relocation operations");
288 if (I->getSymbol(false) != 0)
289 return error(RelSect, R.r_offset,
290 "non-zero symbol in a secondary N32 relocation");
291 RR.Types.push_back(I->getType(false));
292 ++I;
293 }
294 Out.push_back(std::move(RR));
295 } else {
296 uint32_t PackedType = R.getType(Base::Obj.isMips64EL());
297 Reloc RR{
298 R.r_offset, R.getSymbol(Base::Obj.isMips64EL()), {}, R.r_addend};
299 uint8_t T2 = getPackedRelocationField(PackedType, 1);
300 uint8_t T3 = getPackedRelocationField(PackedType, 2);
301 RR.Types.push_back(getPackedRelocationField(PackedType, 0));
302 if (T2 || T3)
303 RR.Types.push_back(T2);
304 if (T3)
305 RR.Types.push_back(T3);
306 uint8_t SSym = getPackedRelocationField(PackedType, 3);
307 if (SSym != ELF::RSS_UNDEF)
308 return error(RelSect, R.r_offset,
309 "unsupported packed relocation special symbol " +
310 Twine(SSym));
311 Out.push_back(std::move(RR));
312 }
313 }
314 return Error::success();
315 }
316
317 auto Rs = Base::Obj.rels(RelSect);
318 if (!Rs)
319 return Rs.takeError();
320 for (auto I = Rs->begin(), E = Rs->end(); I != E;) {
321 const Rel &R = *I++;
322 Reloc RR{R.r_offset, R.getSymbol(false), {}, 0};
323 RR.Types.push_back(R.getType(false));
324 if (ABI == MipsABI::N32) {
325 while (I != E && I->r_offset == R.r_offset) {
326 if (RR.Types.size() == MaxRelocationOperations)
327 return error(RelSect, R.r_offset,
328 "more than three N32 relocation operations");
329 if (I->getSymbol(false) != 0)
330 return error(RelSect, R.r_offset,
331 "non-zero symbol in a secondary N32 relocation");
332 RR.Types.push_back(I->getType(false));
333 ++I;
334 }
335 }
336 Out.push_back(std::move(RR));
337 }
338
339 for (size_t I = 0; I != Out.size(); ++I) {
340 auto &R = Out[I];
341 uint8_t FinalType = R.Types.back();
342 auto Addend = implicitAddend(RelSect, FinalType, B, R.Offset);
343 if (!Addend)
344 return Addend.takeError();
345 R.Addend = *Addend;
346 bool IsLocal = false;
347 if (auto *S = Base::getGraphSymbol(R.Symbol))
348 IsLocal = S->getScope() == Scope::Local;
349 uint8_t LowType = matchingLow(R.Types.front(), IsLocal);
350 if (LowType == ELF::R_MIPS_NONE)
351 continue;
352 bool Found = false;
353 for (size_t J = I + 1; J != Out.size(); ++J)
354 if (Out[J].Types.front() == LowType && Out[J].Symbol == R.Symbol) {
355 auto LowAddend = implicitAddend(RelSect, LowType, B, Out[J].Offset);
356 if (!LowAddend)
357 return LowAddend.takeError();
358 R.Addend += *LowAddend;
359 Found = true;
360 break;
361 }
362 if (!Found)
363 return error(RelSect, R.Offset,
364 "unmatched " +
366 ELF::EM_MIPS, R.Types.front())) +
367 " relocation");
368 }
369 return Error::success();
370 }
371
372 Expected<Edge::Kind> edgeKind(const Reloc &R, Symbol &Target) const {
373 if (R.Types.size() > 1) {
374 if (R.Types.size() == 2 && R.Types[1] == ELF::R_MIPS_64) {
375 switch (R.Types[0]) {
376 case ELF::R_MIPS_32:
377 case ELF::R_MIPS_64:
378 return Pointer64;
379 case ELF::R_MIPS_PC32:
380 return Delta64;
381 case ELF::R_MIPS_GPREL32:
382 return GPRel64;
383 default:
384 break;
385 }
386 }
387 if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 &&
388 R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_HI16)
389 return NegGPRelHi16;
390 if (R.Types.size() == 3 && R.Types[0] == ELF::R_MIPS_GPREL16 &&
391 R.Types[1] == ELF::R_MIPS_SUB && R.Types[2] == ELF::R_MIPS_LO16)
392 return NegGPRelLo16;
393 return make_error<JITLinkError>("unsupported packed MIPS relocation " +
394 getRelocationChainName(R.Types));
395 }
396
397 StringRef Name = Target.hasName() ? *Target.getName() : StringRef();
398 switch (R.Types.front()) {
399 case ELF::R_MIPS_16:
400 return Abs16;
401 case ELF::R_MIPS_32:
402 return Pointer32;
403 case ELF::R_MIPS_64:
404 return Pointer64;
405 case ELF::R_MIPS_HI16:
406 return Name == GPDispName ? GPDispHi16 : Hi16;
407 case ELF::R_MIPS_LO16:
408 return Name == GPDispName ? GPDispLo16 : Lo16;
409 case ELF::R_MIPS_HIGHER:
410 return Higher16;
411 case ELF::R_MIPS_HIGHEST:
412 return Highest16;
413 case ELF::R_MIPS_26:
414 return Jump26;
415 case ELF::R_MIPS_PC16:
416 return PC16;
417 case ELF::R_MIPS_PC32:
418 return PC32;
419 case ELF::R_MIPS_PC18_S3:
420 return PC18S3;
421 case ELF::R_MIPS_PC19_S2:
422 return PC19S2;
423 case ELF::R_MIPS_PC21_S2:
424 return PC21S2;
425 case ELF::R_MIPS_PC26_S2:
426 return PC26S2;
427 case ELF::R_MIPS_PCHI16:
428 return PCHi16;
429 case ELF::R_MIPS_PCLO16:
430 return PCLo16;
431 case ELF::R_MIPS_GPREL16:
432 return GPRel16;
433 case ELF::R_MIPS_GPREL32:
434 return GPRel32;
435 case ELF::R_MIPS_GOT16:
436 return Target.getScope() == Scope::Local
439 case ELF::R_MIPS_CALL16:
440 case ELF::R_MIPS_GOT_DISP:
442 case ELF::R_MIPS_GOT_PAGE:
444 case ELF::R_MIPS_GOT_OFST:
445 return GOTPageOffset16;
446 case ELF::R_MIPS_GOT_HI16:
447 case ELF::R_MIPS_CALL_HI16:
449 case ELF::R_MIPS_GOT_LO16:
450 case ELF::R_MIPS_CALL_LO16:
452 case ELF::R_MIPS_TLS_GD:
454 case ELF::R_MIPS_TLS_LDM:
456 case ELF::R_MIPS_TLS_DTPREL_HI16:
457 return DTPRelHi16;
458 case ELF::R_MIPS_TLS_DTPREL_LO16:
459 return DTPRelLo16;
460 case ELF::R_MIPS_TLS_DTPREL32:
461 return DTPRel32;
462 case ELF::R_MIPS_TLS_DTPREL64:
463 return DTPRel64;
464 case ELF::R_MIPS_TLS_GOTTPREL:
465 case ELF::R_MIPS_TLS_TPREL32:
466 case ELF::R_MIPS_TLS_TPREL64:
467 case ELF::R_MIPS_TLS_TPREL_HI16:
468 case ELF::R_MIPS_TLS_TPREL_LO16:
470 "initial/local-exec MIPS TLS relocations are unsupported");
471 default:
472 return make_error<JITLinkError>("unsupported MIPS relocation " +
474 ELF::EM_MIPS, R.Types.front())));
475 }
476 }
477
478 Error addRelocations() override {
479 if (auto Err = validateSymbols())
480 return Err;
481 for (const auto &RelSect : Base::Sections) {
482 if (RelSect.sh_type != ELF::SHT_REL && RelSect.sh_type != ELF::SHT_RELA)
483 continue;
484 if ((ABI != MipsABI::O32) != (RelSect.sh_type == ELF::SHT_RELA))
486 Base::G->getName() +
487 ": invalid MIPS relocation-section format for ABI");
488 auto FixupSect = Base::Obj.getSection(RelSect.sh_info);
489 if (!FixupSect)
490 return FixupSect.takeError();
491 Block *B = Base::getGraphBlock(RelSect.sh_info);
492 if (!B)
493 continue;
495 if (auto Err = collectRelocs(RelSect, *B, Rs))
496 return Err;
497 for (const Reloc &R : Rs) {
498 uint8_t Primary = R.Types.front();
499 if (Primary == ELF::R_MIPS_NONE || Primary == ELF::R_MIPS_JALR)
500 continue;
502 if (!Target)
503 return error(**FixupSect, R.Offset,
504 "relocation references missing symbol index " +
505 Twine(R.Symbol));
506 auto Kind = edgeKind(R, *Target);
507 if (!Kind)
508 return joinErrors(
509 error(**FixupSect, R.Offset, "cannot lower relocation"),
510 Kind.takeError());
511 auto FixupAddress = orc::ExecutorAddr((*FixupSect)->sh_addr) + R.Offset;
512 Edge::OffsetT Offset = FixupAddress - B->getAddress();
513 unsigned FixupSize = getFixupSize(*Kind);
514 if (Offset > B->getSize() || FixupSize > B->getSize() - Offset)
515 return error(**FixupSect, R.Offset,
516 "relocation fixup extends past the end of its block");
517 B->addEdge(*Kind, Offset, *Target, R.Addend);
518 }
519 }
520 return Error::success();
521 }
522};
523
524static Symbol &getOrCreateTLSBase(LinkGraph &G) {
525 auto Name = G.intern(TLSBaseName);
526 if (auto *S = G.findDefinedSymbolByName(Name))
527 return *S;
528 Section *TLS = G.findSectionByName(".tdata");
529 if (!TLS || TLS->empty())
530 TLS = G.findSectionByName(".tbss");
531 if (!TLS || TLS->empty()) {
532 auto &S =
533 G.createSection(".tdata", orc::MemProt::Read | orc::MemProt::Write);
534 auto &B = G.createMutableContentBlock(S, 0, orc::ExecutorAddr(), 1, 0);
535 return G.addDefinedSymbol(B, 0, Name, 0, Linkage::Strong, Scope::Local,
536 false, true);
537 }
538 auto &B = **TLS->blocks().begin();
539 return G.addDefinedSymbol(B, 0, Name, 0, Linkage::Strong, Scope::Local, false,
540 true);
541}
542
543class MipsTableManager {
544public:
545 explicit MipsTableManager(LinkGraph &G) : G(G) {}
546
547 bool visitEdge(LinkGraph &, Block *, Edge &E) {
548 switch (E.getKind()) {
550 rewriteGOT(E, GOTEntryKind::Exact, GOTOffset16);
551 return true;
553 rewriteGOT(E, GOTEntryKind::Page, GOTOffset16);
554 return true;
556 rewriteGOT(E, GOTEntryKind::Exact, GOTOffsetHi16);
557 return true;
559 rewriteGOT(E, GOTEntryKind::Exact, GOTOffsetLo16);
560 return true;
562 rewriteTLS(E, TLSDescriptorKind::GeneralDynamic);
563 return true;
565 rewriteTLS(E, TLSDescriptorKind::LocalDynamic);
566 return true;
567 case Jump26:
568 if (!E.getTarget().isDefined()) {
569 rewriteBranchToStub(E);
570 return true;
571 }
572 return false;
573 case PC26S2:
574 if (mips::isR6(G) && !E.getTarget().isDefined()) {
575 rewriteBranchToStub(E);
576 return true;
577 }
578 return false;
579 default:
580 return false;
581 }
582 }
583
584private:
585 enum class GOTEntryKind { Exact, Page };
586 enum class TLSDescriptorKind { GeneralDynamic, LocalDynamic };
587
588 using GOTKey = std::tuple<Symbol *, int64_t, GOTEntryKind>;
589 using StubKey = std::tuple<Symbol *, int64_t>;
590 LinkGraph &G;
594 Symbol *TLSLDMEntry = nullptr;
595
596 Section &getSection(StringRef Name, orc::MemProt Prot) {
597 if (auto *S = G.findSectionByName(Name))
598 return *S;
599 return G.createSection(Name, Prot);
600 }
601
602 Symbol &getGOT(Symbol &Target, int64_t Addend, GOTEntryKind Kind) {
603 GOTKey Key{&Target, Addend, Kind};
604 auto I = GOTEntries.find(Key);
605 if (I != GOTEntries.end())
606 return *I->second;
607 auto &Sec =
608 getSection(GOTSectionName, orc::MemProt::Read | orc::MemProt::Write);
609 auto &Entry = mips::createAnonymousPointer(G, Sec);
610 Edge::Kind PointerKind = Kind == GOTEntryKind::Page
611 ? getPagePointerEdgeKind(G)
613 Entry.getBlock().addEdge(PointerKind, 0, Target, Addend);
614 GOTEntries[Key] = &Entry;
615 return Entry;
616 }
617
618 void rewriteGOT(Edge &E, GOTEntryKind EntryKind, Edge::Kind NewKind) {
619 Symbol &Entry = getGOT(E.getTarget(), E.getAddend(), EntryKind);
620 E.setKind(NewKind);
621 E.setTarget(Entry);
622 E.setAddend(0);
623 }
624
625 Symbol &createTLSInfo(Symbol &Target, int64_t Addend) {
626 auto &Sec = getSection(TLSInfoSectionName,
628 auto &B =
629 G.createMutableContentBlock(Sec, 2 * G.getPointerSize(),
630 orc::ExecutorAddr(), G.getPointerSize(), 0);
631 B.addEdge(mips::getPointerEdgeKind(G), G.getPointerSize(), Target, Addend);
632 return G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
633 }
634
635 void rewriteTLS(Edge &E, TLSDescriptorKind Kind) {
636 Symbol *Entry = nullptr;
637 if (Kind == TLSDescriptorKind::LocalDynamic) {
638 if (!TLSLDMEntry)
639 TLSLDMEntry = &createTLSInfo(getOrCreateTLSBase(G), 0);
640 Entry = TLSLDMEntry;
641 } else {
642 auto Key = std::make_pair(&E.getTarget(), E.getAddend());
643 auto I = TLSGDEntries.find(Key);
644 if (I == TLSGDEntries.end())
645 I = TLSGDEntries
646 .try_emplace(Key, &createTLSInfo(E.getTarget(), E.getAddend()))
647 .first;
648 Entry = I->second;
649 }
650 E.setKind(GOTOffset16);
651 E.setTarget(*Entry);
652 E.setAddend(0);
653 }
654
655 void rewriteBranchToStub(Edge &E) {
656 // PC26_S2 uses PC + 4; JITLink edges use the fixup address.
657 int64_t PointerAddend = E.getAddend();
658 int64_t BranchAddend = 0;
659 if (E.getKind() == PC26S2) {
660 PointerAddend += CompactBranchPCBias;
661 BranchAddend = -CompactBranchPCBias;
662 }
663
664 StubKey Key{&E.getTarget(), PointerAddend};
665 auto I = Stubs.find(Key);
666 if (I == Stubs.end()) {
667 auto &Ptr = getGOT(E.getTarget(), PointerAddend, GOTEntryKind::Exact);
668 auto &Sec =
669 getSection(StubsSectionName, orc::MemProt::Read | orc::MemProt::Exec);
670 I = Stubs
673 .first;
674 }
675 E.setTarget(*I->second);
676 E.setAddend(BranchAddend);
677 }
678};
679
680static Error buildTables(LinkGraph &G) {
681 MipsTableManager Tables(G);
682 visitExistingEdges(G, Tables);
683 return Error::success();
684}
685
686static Symbol &defineMagic(LinkGraph &G, Block &Anchor, StringRef Name,
688 auto N = G.intern(Name);
689 if (auto *S = G.findDefinedSymbolByName(N)) {
690 S->setLive(true);
691 return *S;
692 }
693 if (auto *S = G.findExternalSymbolByName(N)) {
694 G.makeDefined(*S, Anchor, Offset, 0, Linkage::Strong, Scope::Local, true);
695 return *S;
696 }
697 return G.addDefinedSymbol(Anchor, Offset, N, 0, Linkage::Strong, Scope::Local,
698 false, true);
699}
700
701static void prepareGPRegion(LinkGraph &G,
702 ArrayRef<std::string> GPRelSectionNames) {
703 Section *GOT = G.findSectionByName(GOTSectionName);
704 if (!GOT)
705 GOT = &G.createSection(GOTSectionName,
707 // Keep the reserved GP window as content so it can share the GOT section.
708 auto &Anchor = G.createMutableContentBlock(
709 *GOT, GPAnchorOffset, orc::ExecutorAddr(), G.getPointerSize(), 0);
710 defineMagic(G, Anchor, GOTSymbolName, 0);
711 defineMagic(G, Anchor, GPName, GPAnchorOffset);
712 defineMagic(G, Anchor, GPDispName, GPAnchorOffset);
713 defineMagic(G, Anchor, LocalGPName, GPAnchorOffset);
714
715 for (const std::string &Name : GPRelSectionNames)
716 if (auto *S = G.findSectionByName(Name)) {
717 SmallVector<Block *> Blocks(S->blocks().begin(), S->blocks().end());
718 for (auto *B : Blocks)
719 G.transferBlock(*B, *GOT);
720 }
721}
722
723static Error orderGPRegion(LinkGraph &G) {
724 auto *GOT = G.findSectionByName(GOTSectionName);
725 if (!GOT)
726 return Error::success();
727
728 if (auto *TLSInfo = G.findSectionByName(TLSInfoSectionName))
729 G.mergeSections(*GOT, *TLSInfo);
730
731 auto *GOTBase = G.findDefinedSymbolByName(G.intern(GOTSymbolName));
732 assert(GOTBase && &GOTBase->getBlock().getSection() == GOT &&
733 GOTBase->getOffset() == 0 && "invalid MIPS GOT base");
734
735 // BasicLayout orders equal-address blocks by size. Give synthesized entries
736 // the anchor's end address to keep the reserved GP window first.
737 Block &Anchor = GOTBase->getBlock();
739 for (auto *B : GOT->blocks())
740 if (B != &Anchor)
741 B->setAddress(orc::ExecutorAddr(Anchor.getSize()));
742
743 return Error::success();
744}
745
746template <typename ELFT>
747Error validateABIFlags(const object::ELFFile<ELFT> &Obj, MipsABI ABI,
748 StringRef FileName) {
749 auto Sections = Obj.sections();
750 if (!Sections)
751 return Sections.takeError();
752 const typename ELFT::Shdr *ABIFlagsSec = nullptr;
753 for (const auto &Sec : *Sections)
754 if (Sec.sh_type == ELF::SHT_MIPS_ABIFLAGS) {
755 if (ABIFlagsSec)
756 return make_error<JITLinkError>(FileName.str() +
757 ": multiple .MIPS.abiflags sections");
758 ABIFlagsSec = &Sec;
759 }
760 if (!ABIFlagsSec)
761 return Error::success();
762 auto Contents = Obj.template getSectionContentsAsArray<char>(*ABIFlagsSec);
763 if (!Contents)
764 return Contents.takeError();
765 if (Contents->size() != sizeof(object::Elf_Mips_ABIFlags<ELFT>))
766 return make_error<JITLinkError>(FileName.str() +
767 ": invalid .MIPS.abiflags size");
768 const auto &AF = *reinterpret_cast<const object::Elf_Mips_ABIFlags<ELFT> *>(
769 Contents->data());
770 if (AF.version != 0)
771 return make_error<JITLinkError>(FileName.str() +
772 ": unsupported .MIPS.abiflags version");
773 if ((ABI == MipsABI::N32 || ABI == MipsABI::N64) &&
774 AF.gpr_size != Mips::AFL_REG_64)
776 FileName.str() + ": N32/N64 requires 64-bit general registers");
777 if (static_cast<uint32_t>(AF.ases) &
780 FileName.str() +
781 ": MIPS16 and microMIPS ABI flags are unsupported by JITLink");
782 return Error::success();
783}
784
785template <typename ELFT>
787buildGraph(object::ELFObjectFile<ELFT> &ObjFile,
788 std::shared_ptr<orc::SymbolStringPool> SSP, MipsABI ABI, Triple TT,
789 SubtargetFeatures Features) {
790 auto &Obj = ObjFile.getELFFile();
791 if (auto Err = validateABIFlags(Obj, ABI, ObjFile.getFileName()))
792 return std::move(Err);
793 ELFLinkGraphBuilder_mips<ELFT> Builder(ObjFile.getFileName(), Obj,
794 std::move(SSP), std::move(TT),
795 std::move(Features), ABI);
796 auto G = Builder.buildGraph();
797 if (!G)
798 return G.takeError();
799
800 SmallVector<std::string> GPRelSections;
801 auto Sections = Obj.sections();
802 if (!Sections)
803 return Sections.takeError();
804 for (const auto &Sec : *Sections)
805 if (Sec.sh_flags & ELF::SHF_MIPS_GPREL) {
806 auto Name = Obj.getSectionName(Sec);
807 if (!Name)
808 return Name.takeError();
809 GPRelSections.push_back(Name->str());
810 }
811 prepareGPRegion(**G, GPRelSections);
812 return G;
813}
814
815static Expected<MipsABI> validateHeader(const object::ELFObjectFileBase &Obj,
816 uint8_t ELFClass, StringRef FileName) {
817 uint32_t Flags = Obj.getPlatformFlags();
820 FileName.str() +
821 ": MIPS16 and microMIPS objects are unsupported by JITLink");
822
823 uint32_t ABIFlag = Flags & ELF::EF_MIPS_ABI;
824 if (ELFClass == ELF::ELFCLASS64) {
825 if ((Flags & ELF::EF_MIPS_ABI2) || ABIFlag != 0)
827 FileName.str() + ": inconsistent MIPS N64 ELF class/ABI flags");
828 return MipsABI::N64;
829 }
830 if (Flags & ELF::EF_MIPS_ABI2) {
831 if (ABIFlag != 0)
833 FileName.str() + ": inconsistent MIPS N32 ELF class/ABI flags");
834 return MipsABI::N32;
835 }
836 if (ABIFlag != 0 && ABIFlag != ELF::EF_MIPS_ABI_O32)
837 return make_error<JITLinkError>(FileName.str() +
838 ": unsupported 32-bit MIPS ABI flags");
839 return MipsABI::O32;
840}
841
842} // namespace
843
844namespace llvm {
845namespace jitlink {
846
847Expected<std::unique_ptr<LinkGraph>>
849 std::shared_ptr<orc::SymbolStringPool> SSP) {
850 StringRef FileName = ObjectBuffer.getBufferIdentifier();
851 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
852 if (!ELFObj)
853 return ELFObj.takeError();
854 auto &Base = cast<object::ELFObjectFileBase>(**ELFObj);
855 assert(Base.getEMachine() == ELF::EM_MIPS && "expected an ELF/MIPS object");
856
857 StringRef Buf = ObjectBuffer.getBuffer();
858 uint8_t Class = Buf[ELF::EI_CLASS];
860 auto ABI = validateHeader(Base, Class, FileName);
861 if (!ABI)
862 return ABI.takeError();
863 auto Features = Base.getFeatures();
864 if (!Features)
865 return Features.takeError();
866
867 Triple TT = Base.makeTriple();
868 if (*ABI == MipsABI::N32) {
870 TT.setEnvironment(Triple::GNUABIN32);
871 }
872
873 if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2LSB)
874 return buildGraph(cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj),
875 std::move(SSP), *ABI, TT, std::move(*Features));
876 if (Class == ELF::ELFCLASS32 && Data == ELF::ELFDATA2MSB)
877 return buildGraph(cast<object::ELFObjectFile<object::ELF32BE>>(**ELFObj),
878 std::move(SSP), *ABI, TT, std::move(*Features));
879 if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2LSB)
880 return buildGraph(cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj),
881 std::move(SSP), *ABI, TT, std::move(*Features));
882 if (Class == ELF::ELFCLASS64 && Data == ELF::ELFDATA2MSB)
883 return buildGraph(cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj),
884 std::move(SSP), *ABI, TT, std::move(*Features));
885 llvm_unreachable("invalid ELF/MIPS class or byte order");
886}
887
888void link_ELF_mips(std::unique_ptr<LinkGraph> G,
889 std::unique_ptr<JITLinkContext> Ctx) {
890 PassConfiguration Config;
891 const Triple &TT = G->getTargetTriple();
892 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
893 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
894 Config.PrePrunePasses.push_back(
895 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64,
897 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
898 if (auto MarkLive = Ctx->getMarkLivePass(TT))
899 Config.PrePrunePasses.push_back(std::move(MarkLive));
900 else
901 Config.PrePrunePasses.push_back(markAllSymbolsLive);
902 Config.PostPrunePasses.push_back(buildTables);
903 }
904 if (auto Err = Ctx->modifyPassConfig(*G, Config))
905 return Ctx->notifyFailed(std::move(Err));
906 if (Ctx->shouldAddDefaultTargetPasses(TT))
907 Config.PostPrunePasses.push_back(orderGPRegion);
908 ELFJITLinker_mips::link(std::move(Ctx), std::move(G), std::move(Config));
909}
910
911} // namespace jitlink
912} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
static bool isMips64EL(const ELFYAML::Object &Obj)
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
#define P(N)
static StringRef getName(Value *V)
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
#define error(X)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:782
iterator end()
Definition DenseMap.h:702
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:872
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef getBufferIdentifier() const
StringRef getBuffer() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
Manages the enabling and disabling of subtarget specific features.
Target - Wrapper for Target specific information.
const char * getName() const
getName - Get the target name.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
StringRef getFileName() const
Definition Binary.cpp:41
Expected< Elf_Sym_Range > symbols(const Elf_Shdr *Sec) const
Definition ELF.h:415
Expected< Elf_Rela_Range > relas(const Elf_Shdr &Sec) const
Definition ELF.h:421
Expected< StringRef > getSectionName(const Elf_Shdr &Section, WarningHandler WarnHandler=&defaultWarningHandler) const
Definition ELF.h:1437
Expected< Elf_Rel_Range > rels(const Elf_Shdr &Sec) const
Definition ELF.h:425
Expected< const Elf_Shdr * > getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, DataRegion< Elf_Word > ShndxTable) const
Definition ELF.h:650
const ELFFile< ELFT > & getELFFile() const
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Represents an address in the executor process.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHF_MIPS_GPREL
Definition ELF.h:1342
@ EI_DATA
Definition ELF.h:56
@ EI_CLASS
Definition ELF.h:55
@ EM_MIPS
Definition ELF.h:146
@ STO_MIPS_MICROMIPS
Definition ELF.h:602
@ STO_MIPS_MIPS16
Definition ELF.h:603
@ SHT_MIPS_REGINFO
Definition ELF.h:1235
@ SHT_MIPS_OPTIONS
Definition ELF.h:1236
@ SHT_REL
Definition ELF.h:1165
@ SHT_RELA
Definition ELF.h:1160
@ SHT_MIPS_ABIFLAGS
Definition ELF.h:1238
@ EF_MIPS_ABI
Definition ELF.h:538
@ EF_MIPS_MICROMIPS
Definition ELF.h:563
@ EF_MIPS_ABI_O32
Definition ELF.h:534
@ EF_MIPS_ARCH_ASE_M16
Definition ELF.h:564
@ EF_MIPS_ABI2
Definition ELF.h:526
@ ELFDATA2MSB
Definition ELF.h:341
@ ELFDATA2LSB
Definition ELF.h:340
@ RSS_UNDEF
Definition ELF.h:1462
@ ELFCLASS64
Definition ELF.h:334
@ ELFCLASS32
Definition ELF.h:333
LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)
Definition ELF.cpp:25
MemProt
Describes Read/Write/Exec permissions for memory.
Definition MemoryFlags.h:27
uint32_t read32(const void *P, endianness E)
Definition Endian.h:392
uint64_t read64(const void *P, endianness E)
Definition Endian.h:395
uint16_t read16(const void *P, endianness E)
Definition Endian.h:389
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition MathExtras.h:567
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
#define N