1 //===----- ELF_i386.cpp - JIT linker implementation for ELF/i386 ----===//
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
7 //===----------------------------------------------------------------------===//
9 // ELF/i386 jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_i386.h"
14 #include "DefineExternalSectionStartAndEndSymbols.h"
15 #include "ELFLinkGraphBuilder.h"
16 #include "JITLinkGeneric.h"
17 #include "llvm/BinaryFormat/ELF.h"
18 #include "llvm/ExecutionEngine/JITLink/i386.h"
19 #include "llvm/Object/ELFObjectFile.h"
21 #define DEBUG_TYPE "jitlink"
24 using namespace llvm::jitlink
;
27 constexpr StringRef ELFGOTSymbolName
= "_GLOBAL_OFFSET_TABLE_";
29 Error
buildTables_ELF_i386(LinkGraph
&G
) {
30 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
32 i386::GOTTableManager GOT
;
33 i386::PLTTableManager
PLT(GOT
);
34 visitExistingEdges(G
, GOT
, PLT
);
35 return Error::success();
39 namespace llvm::jitlink
{
41 class ELFJITLinker_i386
: public JITLinker
<ELFJITLinker_i386
> {
42 friend class JITLinker
<ELFJITLinker_i386
>;
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
)) {
48 getPassConfig().PostAllocationPasses
.push_back(
49 [this](LinkGraph
&G
) { return getOrCreateGOTSymbol(G
); });
53 Symbol
*GOTSymbol
= nullptr;
55 Error
getOrCreateGOTSymbol(LinkGraph
&G
) {
56 auto DefineExternalGOTSymbolIfPresent
=
57 createDefineExternalSectionStartAndEndSymbolsPass(
58 [&](LinkGraph
&LG
, Symbol
&Sym
) -> SectionRangeSymbolDesc
{
59 if (Sym
.getName() == ELFGOTSymbolName
)
60 if (auto *GOTSection
= G
.findSectionByName(
61 i386::GOTTableManager::getSectionName())) {
63 return {*GOTSection
, true};
68 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
70 if (auto Err
= DefineExternalGOTSymbolIfPresent(G
))
73 // If we succeeded then we're done.
75 return Error::success();
77 // Otherwise look for a GOT section: If it already has a start symbol we'll
78 // record it, otherwise we'll create our own.
79 // If there's a GOT section but we didn't find an external GOT symbol...
80 if (auto *GOTSection
=
81 G
.findSectionByName(i386::GOTTableManager::getSectionName())) {
83 // Check for an existing defined symbol.
84 for (auto *Sym
: GOTSection
->symbols())
85 if (Sym
->getName() == ELFGOTSymbolName
) {
87 return Error::success();
90 // If there's no defined symbol then create one.
91 SectionRange
SR(*GOTSection
);
95 &G
.addAbsoluteSymbol(ELFGOTSymbolName
, orc::ExecutorAddr(), 0,
96 Linkage::Strong
, Scope::Local
, true);
99 &G
.addDefinedSymbol(*SR
.getFirstBlock(), 0, ELFGOTSymbolName
, 0,
100 Linkage::Strong
, Scope::Local
, false, true);
104 return Error::success();
107 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
108 return i386::applyFixup(G
, B
, E
, GOTSymbol
);
112 template <typename ELFT
>
113 class ELFLinkGraphBuilder_i386
: public ELFLinkGraphBuilder
<ELFT
> {
115 static Expected
<i386::EdgeKind_i386
> getRelocationKind(const uint32_t Type
) {
116 using namespace i386
;
118 case ELF::R_386_NONE
:
119 return EdgeKind_i386::None
;
121 return EdgeKind_i386::Pointer32
;
122 case ELF::R_386_PC32
:
123 return EdgeKind_i386::PCRel32
;
125 return EdgeKind_i386::Pointer16
;
126 case ELF::R_386_PC16
:
127 return EdgeKind_i386::PCRel16
;
128 case ELF::R_386_GOT32
:
129 return EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT
;
130 case ELF::R_386_GOTPC
:
131 return EdgeKind_i386::Delta32
;
132 case ELF::R_386_GOTOFF
:
133 return EdgeKind_i386::Delta32FromGOT
;
134 case ELF::R_386_PLT32
:
135 return EdgeKind_i386::BranchPCRel32
;
138 return make_error
<JITLinkError
>("Unsupported i386 relocation:" +
139 formatv("{0:d}", Type
));
142 Error
addRelocations() override
{
143 LLVM_DEBUG(dbgs() << "Adding relocations\n");
144 using Base
= ELFLinkGraphBuilder
<ELFT
>;
145 using Self
= ELFLinkGraphBuilder_i386
;
147 for (const auto &RelSect
: Base::Sections
) {
148 // Validate the section to read relocation entries from.
149 if (RelSect
.sh_type
== ELF::SHT_RELA
)
150 return make_error
<StringError
>(
151 "No SHT_RELA in valid i386 ELF object files",
152 inconvertibleErrorCode());
154 if (Error Err
= Base::forEachRelRelocation(RelSect
, this,
155 &Self::addSingleRelocation
))
159 return Error::success();
162 Error
addSingleRelocation(const typename
ELFT::Rel
&Rel
,
163 const typename
ELFT::Shdr
&FixupSection
,
165 using Base
= ELFLinkGraphBuilder
<ELFT
>;
167 uint32_t SymbolIndex
= Rel
.getSymbol(false);
168 auto ObjSymbol
= Base::Obj
.getRelocationSymbol(Rel
, Base::SymTabSec
);
170 return ObjSymbol
.takeError();
172 Symbol
*GraphSymbol
= Base::getGraphSymbol(SymbolIndex
);
174 return make_error
<StringError
>(
175 formatv("Could not find symbol at given index, did you add it to "
176 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
177 SymbolIndex
, (*ObjSymbol
)->st_shndx
,
178 Base::GraphSymbols
.size()),
179 inconvertibleErrorCode());
181 Expected
<i386::EdgeKind_i386
> Kind
= getRelocationKind(Rel
.getType(false));
183 return Kind
.takeError();
185 auto FixupAddress
= orc::ExecutorAddr(FixupSection
.sh_addr
) + Rel
.r_offset
;
189 case i386::EdgeKind_i386::Delta32
: {
190 const char *FixupContent
= BlockToFix
.getContent().data() +
191 (FixupAddress
- BlockToFix
.getAddress());
192 Addend
= *(const support::ulittle32_t
*)FixupContent
;
199 Edge::OffsetT Offset
= FixupAddress
- BlockToFix
.getAddress();
200 Edge
GE(*Kind
, Offset
, *GraphSymbol
, Addend
);
203 printEdge(dbgs(), BlockToFix
, GE
, i386::getEdgeKindName(*Kind
));
207 BlockToFix
.addEdge(std::move(GE
));
208 return Error::success();
212 ELFLinkGraphBuilder_i386(StringRef FileName
, const object::ELFFile
<ELFT
> &Obj
,
213 Triple TT
, SubtargetFeatures Features
)
214 : ELFLinkGraphBuilder
<ELFT
>(Obj
, std::move(TT
), std::move(Features
),
215 FileName
, i386::getEdgeKindName
) {}
218 Expected
<std::unique_ptr
<LinkGraph
>>
219 createLinkGraphFromELFObject_i386(MemoryBufferRef ObjectBuffer
) {
221 dbgs() << "Building jitlink graph for new input "
222 << ObjectBuffer
.getBufferIdentifier() << "...\n";
225 auto ELFObj
= object::ObjectFile::createELFObjectFile(ObjectBuffer
);
227 return ELFObj
.takeError();
229 auto Features
= (*ELFObj
)->getFeatures();
231 return Features
.takeError();
233 assert((*ELFObj
)->getArch() == Triple::x86
&&
234 "Only i386 (little endian) is supported for now");
236 auto &ELFObjFile
= cast
<object::ELFObjectFile
<object::ELF32LE
>>(**ELFObj
);
237 return ELFLinkGraphBuilder_i386
<object::ELF32LE
>(
238 (*ELFObj
)->getFileName(), ELFObjFile
.getELFFile(),
239 (*ELFObj
)->makeTriple(), std::move(*Features
))
243 void link_ELF_i386(std::unique_ptr
<LinkGraph
> G
,
244 std::unique_ptr
<JITLinkContext
> Ctx
) {
245 PassConfiguration Config
;
246 const Triple
&TT
= G
->getTargetTriple();
247 if (Ctx
->shouldAddDefaultTargetPasses(TT
)) {
248 if (auto MarkLive
= Ctx
->getMarkLivePass(TT
))
249 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
251 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
253 // Add an in-place GOT and PLT build pass.
254 Config
.PostPrunePasses
.push_back(buildTables_ELF_i386
);
256 // Add GOT/Stubs optimizer pass.
257 Config
.PreFixupPasses
.push_back(i386::optimizeGOTAndStubAccesses
);
259 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
260 return Ctx
->notifyFailed(std::move(Err
));
262 ELFJITLinker_i386::link(std::move(Ctx
), std::move(G
), std::move(Config
));
265 } // namespace llvm::jitlink