LLVM 20.0.0git
ELF_i386.cpp
Go to the documentation of this file.
1//===----- ELF_i386.cpp - JIT linker implementation for ELF/i386 ----===//
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/i386 jit-link implementation.
10//
11//===----------------------------------------------------------------------===//
12
15#include "ELFLinkGraphBuilder.h"
16#include "JITLinkGeneric.h"
20
21#define DEBUG_TYPE "jitlink"
22
23using namespace llvm;
24using namespace llvm::jitlink;
25
26namespace {
27constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
28
29Error buildTables_ELF_i386(LinkGraph &G) {
30 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
31
33 i386::PLTTableManager PLT(GOT);
34 visitExistingEdges(G, GOT, PLT);
35 return Error::success();
36}
37} // namespace
38
39namespace llvm::jitlink {
40
41class ELFJITLinker_i386 : public JITLinker<ELFJITLinker_i386> {
42 friend class JITLinker<ELFJITLinker_i386>;
43
44public:
45 ELFJITLinker_i386(std::unique_ptr<JITLinkContext> Ctx,
46 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
47 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
49 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
50 }
51
52private:
53 Symbol *GOTSymbol = nullptr;
54
55 Error getOrCreateGOTSymbol(LinkGraph &G) {
56 auto DefineExternalGOTSymbolIfPresent =
59 if (Sym.getName() != nullptr &&
60 *Sym.getName() == ELFGOTSymbolName)
61 if (auto *GOTSection = G.findSectionByName(
63 GOTSymbol = &Sym;
64 return {*GOTSection, true};
65 }
66 return {};
67 });
68
69 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
70 // external.
71 if (auto Err = DefineExternalGOTSymbolIfPresent(G))
72 return Err;
73
74 // If we succeeded then we're done.
75 if (GOTSymbol)
76 return Error::success();
77
78 // Otherwise look for a GOT section: If it already has a start symbol we'll
79 // record it, otherwise we'll create our own.
80 // If there's a GOT section but we didn't find an external GOT symbol...
81 if (auto *GOTSection =
82 G.findSectionByName(i386::GOTTableManager::getSectionName())) {
83
84 // Check for an existing defined symbol.
85 for (auto *Sym : GOTSection->symbols())
86 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
87 GOTSymbol = Sym;
88 return Error::success();
89 }
90
91 // If there's no defined symbol then create one.
92 SectionRange SR(*GOTSection);
93
94 if (SR.empty()) {
95 GOTSymbol =
96 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
98 } else {
99 GOTSymbol =
100 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
101 Linkage::Strong, Scope::Local, false, true);
102 }
103 }
104
105 return Error::success();
106 }
107
108 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
109 return i386::applyFixup(G, B, E, GOTSymbol);
110 }
111};
112
113template <typename ELFT>
115private:
116 static Expected<i386::EdgeKind_i386> getRelocationKind(const uint32_t Type) {
117 using namespace i386;
118 switch (Type) {
119 case ELF::R_386_NONE:
120 return EdgeKind_i386::None;
121 case ELF::R_386_32:
122 return EdgeKind_i386::Pointer32;
123 case ELF::R_386_PC32:
124 return EdgeKind_i386::PCRel32;
125 case ELF::R_386_16:
126 return EdgeKind_i386::Pointer16;
127 case ELF::R_386_PC16:
128 return EdgeKind_i386::PCRel16;
129 case ELF::R_386_GOT32:
130 return EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT;
131 case ELF::R_386_GOTPC:
132 return EdgeKind_i386::Delta32;
133 case ELF::R_386_GOTOFF:
134 return EdgeKind_i386::Delta32FromGOT;
135 case ELF::R_386_PLT32:
136 return EdgeKind_i386::BranchPCRel32;
137 }
138
139 return make_error<JITLinkError>("Unsupported i386 relocation:" +
140 formatv("{0:d}", Type));
141 }
142
143 Error addRelocations() override {
144 LLVM_DEBUG(dbgs() << "Adding relocations\n");
146 using Self = ELFLinkGraphBuilder_i386;
147
148 for (const auto &RelSect : Base::Sections) {
149 // Validate the section to read relocation entries from.
150 if (RelSect.sh_type == ELF::SHT_RELA)
151 return make_error<StringError>(
152 "No SHT_RELA in valid i386 ELF object files",
154
155 if (Error Err = Base::forEachRelRelocation(RelSect, this,
156 &Self::addSingleRelocation))
157 return Err;
158 }
159
160 return Error::success();
161 }
162
163 Error addSingleRelocation(const typename ELFT::Rel &Rel,
164 const typename ELFT::Shdr &FixupSection,
165 Block &BlockToFix) {
167
168 uint32_t SymbolIndex = Rel.getSymbol(false);
169 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
170 if (!ObjSymbol)
171 return ObjSymbol.takeError();
172
173 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
174 if (!GraphSymbol)
175 return make_error<StringError>(
176 formatv("Could not find symbol at given index, did you add it to "
177 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
178 SymbolIndex, (*ObjSymbol)->st_shndx,
179 Base::GraphSymbols.size()),
181
182 Expected<i386::EdgeKind_i386> Kind = getRelocationKind(Rel.getType(false));
183 if (!Kind)
184 return Kind.takeError();
185
186 auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
187 int64_t Addend = 0;
188
189 switch (*Kind) {
191 break;
200 const char *FixupContent = BlockToFix.getContent().data() +
201 (FixupAddress - BlockToFix.getAddress());
202 Addend = *(const support::little32_t *)FixupContent;
203 break;
204 }
207 const char *FixupContent = BlockToFix.getContent().data() +
208 (FixupAddress - BlockToFix.getAddress());
209 Addend = *(const support::little16_t *)FixupContent;
210 break;
211 }
212 }
213
214 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
215 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
216 LLVM_DEBUG({
217 dbgs() << " ";
218 printEdge(dbgs(), BlockToFix, GE, i386::getEdgeKindName(*Kind));
219 dbgs() << "\n";
220 });
221
222 BlockToFix.addEdge(std::move(GE));
223 return Error::success();
224 }
225
226public:
228 std::shared_ptr<orc::SymbolStringPool> SSP,
229 Triple TT, SubtargetFeatures Features)
230 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
231 std::move(Features), FileName,
232 i386::getEdgeKindName) {}
233};
234
237 std::shared_ptr<orc::SymbolStringPool> SSP) {
238 LLVM_DEBUG({
239 dbgs() << "Building jitlink graph for new input "
240 << ObjectBuffer.getBufferIdentifier() << "...\n";
241 });
242
243 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
244 if (!ELFObj)
245 return ELFObj.takeError();
246
247 auto Features = (*ELFObj)->getFeatures();
248 if (!Features)
249 return Features.takeError();
250
251 assert((*ELFObj)->getArch() == Triple::x86 &&
252 "Only i386 (little endian) is supported for now");
253
254 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
255
257 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
258 (*ELFObj)->makeTriple(), std::move(*Features))
259 .buildGraph();
260}
261
262void link_ELF_i386(std::unique_ptr<LinkGraph> G,
263 std::unique_ptr<JITLinkContext> Ctx) {
265 const Triple &TT = G->getTargetTriple();
266 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
267 if (auto MarkLive = Ctx->getMarkLivePass(TT))
268 Config.PrePrunePasses.push_back(std::move(MarkLive));
269 else
270 Config.PrePrunePasses.push_back(markAllSymbolsLive);
271
272 // Add an in-place GOT and PLT build pass.
273 Config.PostPrunePasses.push_back(buildTables_ELF_i386);
274
275 // Add GOT/Stubs optimizer pass.
276 Config.PreFixupPasses.push_back(i386::optimizeGOTAndStubAccesses);
277 }
278 if (auto Err = Ctx->modifyPassConfig(*G, Config))
279 return Ctx->notifyFailed(std::move(Err));
280
281 ELFJITLinker_i386::link(std::move(Ctx), std::move(G), std::move(Config));
282}
283
284} // namespace llvm::jitlink
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DEBUG(...)
Definition: Debug.h:106
RelaxConfig Config
Definition: ELF_riscv.cpp:506
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define G(x, y, z)
Definition: MD5.cpp:56
if(PassOpts->AAPipeline)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const T * data() const
Definition: ArrayRef.h:165
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
StringRef getBufferIdentifier() const
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Represents an address in the executor process.
@ SHT_RELA
Definition: ELF.h:1093
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858