LLVM: lib/ExecutionEngine/JITLink/ELF_loongarch.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

20

24

25#define DEBUG_TYPE "jitlink"

26

27using namespace llvm;

30

31namespace {

32

33class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> {

34 friend class JITLinker<ELFJITLinker_loongarch>;

35

36public:

37 ELFJITLinker_loongarch(std::unique_ptr Ctx,

38 std::unique_ptr G,

40 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}

41

42private:

45 }

46};

47

48namespace {

49

50struct SymbolAnchor {

53 bool End;

54};

55

56struct BlockRelaxAux {

57

58

60

61

63

64

66

68

69

71};

72

73struct RelaxAux {

75};

76

77}

78

81}

82

84 switch (E.getKind()) {

85 default:

86 return false;

88 return true;

89 }

90}

91

93 RelaxAux Aux;

94 for (auto &S : G.sections()) {

96 continue;

97 for (auto *B : S.blocks()) {

98 auto BlockEmplaceResult = Aux.Blocks.try_emplace(B);

99 assert(BlockEmplaceResult.second && "Block encountered twice");

100 auto &BlockAux = BlockEmplaceResult.first->second;

101

102 for (auto &E : B->edges())

104 BlockAux.RelaxEdges.push_back(&E);

105

106 if (BlockAux.RelaxEdges.empty()) {

107 Aux.Blocks.erase(BlockEmplaceResult.first);

108 continue;

109 }

110

111 const auto NumEdges = BlockAux.RelaxEdges.size();

112 BlockAux.RelocDeltas.resize(NumEdges, 0);

113 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);

114

115

116 for (auto *Sym : S.symbols()) {

117 if (!Sym->isDefined() || &Sym->getBlock() != B)

118 continue;

119

120 BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false});

121 BlockAux.Anchors.push_back(

122 {Sym->getOffset() + Sym->getSize(), Sym, true});

123 }

124 }

125 }

126

127

128

129

130

131 for (auto &BlockAuxIter : Aux.Blocks) {

132 llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) {

133 return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End);

134 });

135 }

136

137 return Aux;

138}

139

141 Edge::Kind &NewEdgeKind) {

143 E.getTarget().isDefined() ? Log2_64(E.getAddend()) + 1 : E.getAddend();

144 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;

146 const uint64_t MaxBytes = Addend >> 8;

148 const uint64_t CurBytes = Off == 0 ? 0 : Align - Off;

149

150

151 if (MaxBytes != 0 && CurBytes > MaxBytes)

152 Remove = AllBytes;

153 else

154 Remove = AllBytes - CurBytes;

155

156 assert(static_cast<int32_t>(Remove) >= 0 &&

157 "R_LARCH_ALIGN needs expanding the content");

159}

160

166

167 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);

168 Aux.Writes.clear();

169

171 const auto Loc = BlockAddr + E->getOffset() - Delta;

172 auto &Cur = Aux.RelocDeltas[I];

174 switch (E->getKind()) {

177 break;

178 default:

180 }

181

182

183

184

186 if (SA[0].End)

187 SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset());

188 else

189 SA[0].Sym->setOffset(SA[0].Offset - Delta);

190 }

191

192 Delta += Remove;

193 if (Delta != Cur) {

194 Cur = Delta;

196 }

197 }

198

199 for (const SymbolAnchor &A : SA) {

200 if (A.End)

201 A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset());

202 else

203 A.Sym->setOffset(A.Offset - Delta);

204 }

205

207}

208

211

212 for (auto &[B, BlockAux] : Aux.Blocks)

214

216}

217

220 auto *Dest = Contents.data();

223

224

225

227 uint32_t Remove = Aux.RelocDeltas[I] - Delta;

228 Delta = Aux.RelocDeltas[I];

229 if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid)

230 continue;

231

232

233 const auto Size = E->getOffset() - Offset;

234 std::memmove(Dest, Contents.data() + Offset, Size);

235 Dest += Size;

236 Offset = E->getOffset() + Remove;

237 }

238

239 std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset);

240

241

242 Delta = 0;

243 size_t I = 0;

245 E.setOffset(E.getOffset() - Delta);

246

247 if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) {

248 if (Aux.EdgeKinds[I] != Edge::Invalid)

249 E.setKind(Aux.EdgeKinds[I]);

250

251 Delta = Aux.RelocDeltas[I];

252 ++I;

253 }

254 }

255

256

257

258

262 else

263 ++IE;

264 }

265}

266

268 for (auto &[B, BlockAux] : Aux.Blocks)

270}

271

275 }

278}

279

280template

282private:

286 switch (Type) {

287 case ELF::R_LARCH_64:

289 case ELF::R_LARCH_32:

291 case ELF::R_LARCH_32_PCREL:

293 case ELF::R_LARCH_B16:

295 case ELF::R_LARCH_B21:

297 case ELF::R_LARCH_B26:

299 case ELF::R_LARCH_PCALA_HI20:

301 case ELF::R_LARCH_PCALA_LO12:

303 case ELF::R_LARCH_GOT_PC_HI20:

305 case ELF::R_LARCH_GOT_PC_LO12:

307 case ELF::R_LARCH_CALL36:

309 case ELF::R_LARCH_ADD6:

311 case ELF::R_LARCH_ADD8:

313 case ELF::R_LARCH_ADD16:

315 case ELF::R_LARCH_ADD32:

317 case ELF::R_LARCH_ADD64:

319 case ELF::R_LARCH_ADD_ULEB128:

321 case ELF::R_LARCH_SUB6:

323 case ELF::R_LARCH_SUB8:

325 case ELF::R_LARCH_SUB16:

327 case ELF::R_LARCH_SUB32:

329 case ELF::R_LARCH_SUB64:

331 case ELF::R_LARCH_SUB_ULEB128:

333 case ELF::R_LARCH_ALIGN:

335 }

336

338 "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) +

340 }

341

343

344 return Kind;

345 }

346

347 Error addRelocations() override {

349

351 using Self = ELFLinkGraphBuilder_loongarch;

352 for (const auto &RelSect : Base::Sections)

353 if (Error Err = Base::forEachRelaRelocation(RelSect, this,

354 &Self::addSingleRelocation))

355 return Err;

356

358 }

359

360 Error addSingleRelocation(const typename ELFT::Rela &Rel,

361 const typename ELFT::Shdr &FixupSect,

362 Block &BlockToFix) {

364

366 int64_t Addend = Rel.r_addend;

367

368

369 if (Type == ELF::R_LARCH_MARK_LA)

371

372 if (Type == ELF::R_LARCH_RELAX) {

375 "R_LARCH_RELAX without preceding relocation",

377

378 auto &PrevEdge = *std::prev(BlockToFix.edges().end());

380 PrevEdge.setKind(getRelaxableRelocationKind(Kind));

382 }

383

385 if (!Kind)

386 return Kind.takeError();

387

388 uint32_t SymbolIndex = Rel.getSymbol(false);

389 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);

390 if (!ObjSymbol)

391 return ObjSymbol.takeError();

392

393 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);

394 if (!GraphSymbol)

396 formatv("Could not find symbol at given index, did you add it to "

397 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",

398 SymbolIndex, (*ObjSymbol)->st_shndx,

399 Base::GraphSymbols.size()),

401

402 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;

403 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();

404 Edge GE(*Kind, Offset, *GraphSymbol, Addend);

406 dbgs() << " ";

408 dbgs() << "\n";

409 });

410

411 BlockToFix.addEdge(std::move(GE));

412

414 }

415

416public:

417 ELFLinkGraphBuilder_loongarch(StringRef FileName,

419 std::shared_ptrorc::SymbolStringPool SSP,

422 std::move(Features), FileName,

424};

425

428

433}

434

435}

436

437namespace llvm {

439

441 MemoryBufferRef ObjectBuffer, std::shared_ptrorc::SymbolStringPool SSP) {

443 dbgs() << "Building jitlink graph for new input "

445 });

446

448 if (!ELFObj)

449 return ELFObj.takeError();

450

451 auto Features = (*ELFObj)->getFeatures();

452 if (!Features)

453 return Features.takeError();

454

457 return ELFLinkGraphBuilder_loongarchobject::ELF64LE(

458 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),

459 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))

460 .buildGraph();

461 }

462

464 "Invalid triple for LoongArch ELF object file");

466 return ELFLinkGraphBuilder_loongarchobject::ELF32LE(

467 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),

468 (*ELFObj)->makeTriple(), std::move(*Features))

469 .buildGraph();

470}

471

473 std::unique_ptr Ctx) {

475 const Triple &TT = G->getTargetTriple();

476 if (Ctx->shouldAddDefaultTargetPasses(TT)) {

477

483

484

485 if (auto MarkLive = Ctx->getMarkLivePass(TT))

486 Config.PrePrunePasses.push_back(std::move(MarkLive));

487 else

489

490

491 Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);

492

493

495 }

496

497 if (auto Err = Ctx->modifyPassConfig(*G, Config))

498 return Ctx->notifyFailed(std::move(Err));

499

500 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config));

501}

502

504

505}

506}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

size_t size() const

size - Get the array size.

ArrayRef< T > slice(size_t N, size_t M) const

slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

StringRef getBufferIdentifier() const

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

Manages the enabling and disabling of subtarget specific features.

Triple - Helper class for working with autoconf configuration names.

The instances of the Type class are immutable: once they are created, they are never changed.

orc::ExecutorAddr getAddress() const

An Addressable with content and edges.

edge_iterator removeEdge(edge_iterator I)

Remove the edge pointed to by the given iterator.

void addEdge(Edge::Kind K, Edge::OffsetT Offset, Symbol &Target, Edge::AddendT Addend)

Add an edge to this block.

iterator_range< edge_iterator > edges()

Return the list of edges attached to this content.

MutableArrayRef< char > getAlreadyMutableContent()

Get mutable content for this block.

bool edges_empty() const

Returns true if the list of edges is empty.

A LinkGraph pass that splits blocks in a section that follows the DWARF Record format into sub-blocks...

A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA edges.

LinkGraph building code that's specific to the given ELFT, but common across all architectures.

Represents fixups and constraints in the LinkGraph.

Represents an object file section.

iterator_range< symbol_iterator > symbols()

Returns an iterator over the symbols defined in this section.

iterator_range< block_iterator > blocks()

Returns an iterator over the blocks defined in this section.

orc::MemProt getMemProt() const

Returns the protection flags for this section.

Global Offset Table Builder.

Procedure Linkage Table Builder.

static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)

Represents an address in the executor process.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

LLVM_ABI const char * getEdgeKindName(Edge::Kind K)

Returns a string name for the given loongarch edge.

EdgeKind_loongarch

Represents loongarch fixups.

@ Branch16PCRel

A 16-bit PC-relative branch.

@ Add16

16 bits label addition

@ AddUleb128

ULEB128 bits label addition.

@ RequestGOTAndTransformToPage20

A GOT entry getter/constructor, transformed to Page20 pointing at the GOT entry for the original targ...

@ Sub16

16 bits label subtraction

@ NegDelta32

A 32-bit negative delta.

@ SubUleb128

ULEB128 bits label subtraction.

@ Sub8

8 bits label subtraction

@ PageOffset12

The 12-bit offset of the target within its page.

@ Sub32

32 bits label subtraction

@ Add64

64 bits label addition

@ Sub6

low 6 bits label subtraction

@ Add8

8 bits label addition

@ Page20

The signed 20-bit delta from the fixup page to the page containing the target.

@ Pointer64

A plain 64-bit pointer value relocation.

@ RequestGOTAndTransformToPageOffset12

A GOT entry getter/constructor, transformed to Pageoffset12 pointing at the GOT entry for the origina...

@ Call36PCRel

A 36-bit PC-relative call.

@ Add6

low 6 bits label addition

@ Branch21PCRel

A 21-bit PC-relative branch.

@ Branch26PCRel

A 26-bit PC-relative branch.

@ Add32

32 bits label addition

@ Pointer32

A plain 32-bit pointer value relocation.

@ AlignRelaxable

Alignment requirement used by linker relaxation.

@ Sub64

64 bits label subtraction

Error applyFixup(LinkGraph &G, Block &B, const Edge &E)

Apply fixup expression for edge to block content.

unique_function< Error(LinkGraph &)> LinkGraphPassFunction

A function for mutating LinkGraphs.

static bool shouldRelax(const Section &S)

static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux)

static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove, Edge::Kind &NewEdgeKind)

static bool relaxOnce(LinkGraph &G, RelaxAux &Aux)

static Error relax(LinkGraph &G)

static bool isRelaxable(const Edge &E)

void visitExistingEdges(LinkGraph &G, VisitorTs &&...Vs)

For each edge in the given graph, apply a list of visitors to the edge, stopping when the first visit...

LLVM_ABI Error markAllSymbolsLive(LinkGraph &G)

Marks all symbols in a graph live.

LinkGraphPassFunction createRelaxationPass_ELF_loongarch()

Returns a pass that performs linker relaxation.

Definition ELF_loongarch.cpp:503

static RelaxAux initRelaxAux(LinkGraph &G)

Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)

Create a LinkGraph from an ELF/loongarch relocatable object.

Definition ELF_loongarch.cpp:440

LLVM_ABI void printEdge(raw_ostream &OS, const Block &B, const Edge &E, StringRef EdgeKindName)

static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux, const RelaxConfig &Config)

void link_ELF_loongarch(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)

jit-link the given object buffer, which must be an ELF loongarch object file.

Definition ELF_loongarch.cpp:472

static void finalizeRelax(LinkGraph &G, RelaxAux &Aux)

LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)

This is an optimization pass for GlobalISel generic memory operations.

auto enumerate(FirstRange &&First, RestRanges &&...Rest)

Given two or more input ranges, returns a new range whose values are tuples (A, B,...

LLVM_ABI std::error_code inconvertibleErrorCode()

The value returned by this function can be returned from convertToErrorCode for Error values where no...

unsigned Log2_64(uint64_t Value)

Return the floor log base 2 of the specified value, -1 if the value is zero.

static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

void sort(IteratorTy Start, IteratorTy End)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

ArrayRef(const T &OneElt) -> ArrayRef< T >

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

This struct is a compact representation of a valid (non-zero power of two) alignment.

An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...

LinkGraphPassList PostAllocationPasses

Post-allocation passes.

LinkGraphPassList PostPrunePasses

Post-prune passes.

LinkGraphPassList PrePrunePasses

Pre-prune passes.