Skip to content

Commit 98be16f

Browse files
committed
[JITLink][COFF] Use regular external symbol resolution for __ImageBase.
This fixes a concurrency bug in the COFF_x86_64 backend: lookupAsync was used to find __ImageBase without blocking to wait for the result. Rather than adding promises / futures, this patch just adds an external __ImageBase symbol if needed. This is the canonical JITLink solution for resolving external symbols, and is simpler and more concurrency friendly than using promises / futures with lookupAsync.
1 parent 642c75b commit 98be16f

File tree

3 files changed

+62
-57
lines changed

3 files changed

+62
-57
lines changed

llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,5 +642,39 @@ COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
642642
return GSym;
643643
}
644644

645+
Symbol *GetImageBaseSymbol::operator()(LinkGraph &G) {
646+
if (ImageBase)
647+
return *ImageBase;
648+
649+
auto IBN = G.intern(ImageBaseName);
650+
651+
// Check external symbols for image base.
652+
for (auto *Sym : G.external_symbols()) {
653+
if (Sym->getName() == IBN) {
654+
ImageBase = Sym;
655+
return Sym;
656+
}
657+
}
658+
659+
// Check absolute symbols (unexpected, but legal).
660+
for (auto *Sym : G.absolute_symbols()) {
661+
if (Sym->getName() == IBN) {
662+
ImageBase = Sym;
663+
return Sym;
664+
}
665+
}
666+
667+
// Finally, check defined symbols.
668+
for (auto *Sym : G.defined_symbols()) {
669+
if (Sym->hasName() && Sym->getName() == IBN) {
670+
ImageBase = Sym;
671+
return Sym;
672+
}
673+
}
674+
675+
ImageBase = nullptr;
676+
return nullptr;
677+
}
678+
645679
} // namespace jitlink
646680
} // namespace llvm

llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ class COFFLinkGraphBuilder {
7979
return GraphBlocks[SecIndex];
8080
}
8181

82+
Symbol &addImageBaseSymbol(StringRef Name = "__ImageBase") {
83+
auto &ImageBase = G->addExternalSymbol(G->intern(Name), 0, true);
84+
ImageBase.setLive(true);
85+
return ImageBase;
86+
}
87+
8288
object::COFFObjectFile::section_iterator_range sections() const {
8389
return Obj.sections();
8490
}
@@ -216,6 +222,18 @@ Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
216222
return Error::success();
217223
}
218224

225+
class GetImageBaseSymbol {
226+
public:
227+
GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase")
228+
: ImageBaseName(ImageBaseName) {}
229+
Symbol *operator()(LinkGraph &G);
230+
void reset() { ImageBase = std::nullopt; }
231+
232+
private:
233+
StringRef ImageBaseName;
234+
std::optional<Symbol *> ImageBase;
235+
};
236+
219237
} // end namespace jitlink
220238
} // end namespace llvm
221239

llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp

Lines changed: 10 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
9393

9494
Edge::Kind Kind = Edge::Invalid;
9595
const char *FixupPtr = BlockToFix.getContent().data() + Offset;
96+
Symbol *ImageBase = GetImageBaseSymbol()(getGraph());
9697

9798
switch (Rel.getType()) {
9899
case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
100+
if (!ImageBase)
101+
ImageBase = &addImageBaseSymbol();
99102
Kind = EdgeKind_coff_x86_64::Pointer32NB;
100103
Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
101104
break;
@@ -192,20 +195,15 @@ class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
192195

193196
class COFFLinkGraphLowering_x86_64 {
194197
public:
195-
COFFLinkGraphLowering_x86_64(std::shared_ptr<orc::SymbolStringPool> SSP)
196-
: SSP(std::move(SSP)) {
197-
ImageBaseName = this->SSP->intern("__ImageBase");
198-
}
199198
// Lowers COFF x86_64 specific edges to generic x86_64 edges.
200-
Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
199+
Error operator()(LinkGraph &G) {
201200
for (auto *B : G.blocks()) {
202201
for (auto &E : B->edges()) {
203202
switch (E.getKind()) {
204203
case EdgeKind_coff_x86_64::Pointer32NB: {
205-
auto ImageBase = getImageBaseAddress(G, Ctx);
206-
if (!ImageBase)
207-
return ImageBase.takeError();
208-
E.setAddend(E.getAddend() - ImageBase->getValue());
204+
auto ImageBase = GetImageBase(G);
205+
assert(ImageBase && "__ImageBase symbol must be defined");
206+
E.setAddend(E.getAddend() - ImageBase->getAddress().getValue());
209207
E.setKind(x86_64::Pointer32);
210208
break;
211209
}
@@ -237,61 +235,18 @@ class COFFLinkGraphLowering_x86_64 {
237235
}
238236

239237
private:
240-
const orc::SymbolStringPtr &getImageBaseSymbolName() const {
241-
return this->ImageBaseName;
242-
}
243-
244238
orc::ExecutorAddr getSectionStart(Section &Sec) {
245239
if (!SectionStartCache.count(&Sec)) {
246240
SectionRange Range(Sec);
247241
SectionStartCache[&Sec] = Range.getStart();
242+
return Range.getStart();
248243
}
249244
return SectionStartCache[&Sec];
250245
}
251246

252-
Expected<orc::ExecutorAddr> getImageBaseAddress(LinkGraph &G,
253-
JITLinkContext &Ctx) {
254-
if (this->ImageBase)
255-
return this->ImageBase;
256-
for (auto *S : G.defined_symbols())
257-
if (S->getName() == getImageBaseSymbolName()) {
258-
this->ImageBase = S->getAddress();
259-
return this->ImageBase;
260-
}
261-
262-
JITLinkContext::LookupMap Symbols;
263-
Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
264-
orc::ExecutorAddr ImageBase;
265-
Error Err = Error::success();
266-
Ctx.lookup(Symbols,
267-
createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
268-
ErrorAsOutParameter _(Err);
269-
if (!LR) {
270-
Err = LR.takeError();
271-
return;
272-
}
273-
ImageBase = LR->begin()->second.getAddress();
274-
}));
275-
if (Err)
276-
return std::move(Err);
277-
this->ImageBase = ImageBase;
278-
return ImageBase;
279-
}
280-
247+
GetImageBaseSymbol GetImageBase;
281248
DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
282-
orc::ExecutorAddr ImageBase;
283-
std::shared_ptr<orc::SymbolStringPool> SSP;
284-
orc::SymbolStringPtr ImageBaseName = nullptr;
285249
};
286-
287-
Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
288-
LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
289-
COFFLinkGraphLowering_x86_64 GraphLowering(G.getSymbolStringPool());
290-
if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
291-
return Err;
292-
293-
return Error::success();
294-
}
295250
} // namespace
296251

297252
namespace llvm {
@@ -349,9 +304,7 @@ void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
349304
Config.PrePrunePasses.push_back(markAllSymbolsLive);
350305

351306
// Add COFF edge lowering passes.
352-
JITLinkContext *CtxPtr = Ctx.get();
353-
Config.PreFixupPasses.push_back(
354-
[CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
307+
Config.PreFixupPasses.push_back(COFFLinkGraphLowering_x86_64());
355308
}
356309

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

0 commit comments

Comments
 (0)