1//===------ ELF_hexagon.cpp - JIT linker for ELF/hexagon ------------------===//
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// ELF/hexagon jit-link implementation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ExecutionEngine/JITLink/ELF_hexagon.h"
14#include "ELFLinkGraphBuilder.h"
15#include "JITLinkGeneric.h"
16#include "llvm/BinaryFormat/ELF.h"
17#include "llvm/ExecutionEngine/JITLink/hexagon.h"
18#include "llvm/Object/ELFObjectFile.h"
19
20#define DEBUG_TYPE "jitlink"
21
22using namespace llvm;
23using namespace llvm::jitlink;
24
25namespace {
26
27class ELFJITLinker_hexagon : public JITLinker<ELFJITLinker_hexagon> {
28 friend class JITLinker<ELFJITLinker_hexagon>;
29
30public:
31 ELFJITLinker_hexagon(std::unique_ptr<JITLinkContext> Ctx,
32 std::unique_ptr<LinkGraph> G,
33 PassConfiguration PassConfig)
34 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
35
36private:
37 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
38 return hexagon::applyFixup(G, B, E);
39 }
40};
41
42class ELFLinkGraphBuilder_hexagon
43 : public ELFLinkGraphBuilder<object::ELF32LE> {
44private:
45 using ELFT = object::ELF32LE;
46
47 Expected<hexagon::EdgeKind_hexagon> getRelocationKind(const uint32_t Type) {
48 switch (Type) {
49 case ELF::R_HEX_32:
50 return hexagon::Pointer32;
51 case ELF::R_HEX_32_PCREL:
52 return hexagon::PCRel32;
53 case ELF::R_HEX_B22_PCREL:
54 case ELF::R_HEX_PLT_B22_PCREL:
55 // PLT and GD_PLT variants are mapped to plain branch edges since JITLink
56 // resolves all symbols directly within contiguous JIT memory. When the
57 // GOT/PLT stubs builder is added (see TODO in link_ELF_hexagon), these
58 // should map to a distinct edge kind that triggers stub generation.
59 // GD_PLT does not handle TLS __tls_get_addr calls.
60 case ELF::R_HEX_GD_PLT_B22_PCREL:
61 return hexagon::B22_PCREL;
62 case ELF::R_HEX_B15_PCREL:
63 return hexagon::B15_PCREL;
64 case ELF::R_HEX_B13_PCREL:
65 return hexagon::B13_PCREL;
66 case ELF::R_HEX_B9_PCREL:
67 return hexagon::B9_PCREL;
68 case ELF::R_HEX_B7_PCREL:
69 return hexagon::B7_PCREL;
70 case ELF::R_HEX_HI16:
71 return hexagon::HI16;
72 case ELF::R_HEX_LO16:
73 return hexagon::LO16;
74 case ELF::R_HEX_32_6_X:
75 return hexagon::Word32_6_X;
76 case ELF::R_HEX_B32_PCREL_X:
77 case ELF::R_HEX_GD_PLT_B32_PCREL_X: // See PLT/GD_PLT note above.
78 return hexagon::B32_PCREL_X;
79 case ELF::R_HEX_B22_PCREL_X:
80 case ELF::R_HEX_GD_PLT_B22_PCREL_X: // See PLT/GD_PLT note above.
81 return hexagon::B22_PCREL_X;
82 case ELF::R_HEX_B15_PCREL_X:
83 return hexagon::B15_PCREL_X;
84 case ELF::R_HEX_B13_PCREL_X:
85 return hexagon::B13_PCREL_X;
86 case ELF::R_HEX_B9_PCREL_X:
87 return hexagon::B9_PCREL_X;
88 case ELF::R_HEX_B7_PCREL_X:
89 return hexagon::B7_PCREL_X;
90 case ELF::R_HEX_6_X:
91 return hexagon::Word6_X;
92 case ELF::R_HEX_6_PCREL_X:
93 return hexagon::Word6_PCREL_X;
94 case ELF::R_HEX_8_X:
95 return hexagon::Word8_X;
96 case ELF::R_HEX_9_X:
97 return hexagon::Word9_X;
98 case ELF::R_HEX_10_X:
99 return hexagon::Word10_X;
100 case ELF::R_HEX_11_X:
101 return hexagon::Word11_X;
102 case ELF::R_HEX_12_X:
103 return hexagon::Word12_X;
104 case ELF::R_HEX_16_X:
105 return hexagon::Word16_X;
106 }
107
108 return make_error<JITLinkError>(
109 Args: "In " + G->getName() + ": Unsupported Hexagon relocation type " +
110 object::getELFRelocationTypeName(Machine: ELF::EM_HEXAGON, Type));
111 }
112
113 Error addRelocations() override {
114 LLVM_DEBUG(dbgs() << "Adding relocations\n");
115 using Base = ELFLinkGraphBuilder<ELFT>;
116 using Self = ELFLinkGraphBuilder_hexagon;
117
118 for (const auto &RelSect : Base::Sections) {
119 // Hexagon uses SHT_RELA.
120 if (RelSect.sh_type == ELF::SHT_REL)
121 return make_error<StringError>(
122 Args: "Unexpected SHT_REL section in Hexagon ELF object",
123 Args: inconvertibleErrorCode());
124
125 if (Error Err = Base::forEachRelaRelocation(RelSect, Instance: this,
126 Method: &Self::addSingleRelocation))
127 return Err;
128 }
129
130 return Error::success();
131 }
132
133 Error addSingleRelocation(const typename ELFT::Rela &Rel,
134 const typename ELFT::Shdr &FixupSection,
135 Block &BlockToFix) {
136 using Base = ELFLinkGraphBuilder<ELFT>;
137
138 auto ELFReloc = Rel.getType(isMips64EL: false);
139
140 if (LLVM_UNLIKELY(ELFReloc == ELF::R_HEX_NONE))
141 return Error::success();
142
143 uint32_t SymbolIndex = Rel.getSymbol(isMips64EL: false);
144 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, SymTab: Base::SymTabSec);
145 if (!ObjSymbol)
146 return ObjSymbol.takeError();
147
148 Symbol *GraphSymbol = Base::getGraphSymbol(SymIndex: SymbolIndex);
149 if (!GraphSymbol)
150 return make_error<StringError>(
151 Args: formatv(Fmt: "Could not find symbol at given index, did you add it to "
152 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
153 Vals&: SymbolIndex, Vals: (*ObjSymbol)->st_shndx,
154 Vals: Base::GraphSymbols.size()),
155 Args: inconvertibleErrorCode());
156
157 Expected<hexagon::EdgeKind_hexagon> Kind = getRelocationKind(Type: ELFReloc);
158 if (!Kind)
159 return Kind.takeError();
160
161 auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
162 int64_t Addend = Rel.r_addend;
163
164 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
165 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
166 LLVM_DEBUG({
167 dbgs() << " ";
168 printEdge(dbgs(), BlockToFix, GE, hexagon::getEdgeKindName(*Kind));
169 dbgs() << "\n";
170 });
171
172 BlockToFix.addEdge(E: std::move(GE));
173 return Error::success();
174 }
175
176public:
177 ELFLinkGraphBuilder_hexagon(StringRef FileName,
178 const object::ELFFile<ELFT> &Obj,
179 std::shared_ptr<orc::SymbolStringPool> SSP,
180 Triple TT, SubtargetFeatures Features)
181 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
182 std::move(Features), FileName,
183 hexagon::getEdgeKindName) {}
184};
185
186} // anonymous namespace
187
188namespace llvm::jitlink {
189
190Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_hexagon(
191 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
192 LLVM_DEBUG({
193 dbgs() << "Building jitlink graph for new input "
194 << ObjectBuffer.getBufferIdentifier() << "...\n";
195 });
196
197 auto ELFObj = object::ObjectFile::createELFObjectFile(Object: ObjectBuffer);
198 if (!ELFObj)
199 return ELFObj.takeError();
200
201 auto Features = (*ELFObj)->getFeatures();
202 if (!Features)
203 return Features.takeError();
204
205 assert((*ELFObj)->getArch() == Triple::hexagon &&
206 "Only Hexagon is supported");
207
208 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(Val&: **ELFObj);
209
210 return ELFLinkGraphBuilder_hexagon(
211 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
212 (*ELFObj)->makeTriple(), std::move(*Features))
213 .buildGraph();
214}
215
216void link_ELF_hexagon(std::unique_ptr<LinkGraph> G,
217 std::unique_ptr<JITLinkContext> Ctx) {
218 PassConfiguration Config;
219 const Triple &TT = G->getTargetTriple();
220 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
221 // TODO: Add GOT/PLT stubs builder when external symbol support is needed.
222 // TODO: Add eh-frame passes when exception handling support is needed.
223 if (auto MarkLive = Ctx->getMarkLivePass(TT))
224 Config.PrePrunePasses.push_back(x: std::move(MarkLive));
225 else
226 Config.PrePrunePasses.push_back(x: markAllSymbolsLive);
227 }
228 if (auto Err = Ctx->modifyPassConfig(G&: *G, Config))
229 return Ctx->notifyFailed(Err: std::move(Err));
230
231 ELFJITLinker_hexagon::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config));
232}
233
234} // namespace llvm::jitlink
235