Skip to content

Commit 6a433d7

Browse files
[llvm-jitlink] Allow optional stub-kind filter in stub_addr() expressions (#78369)
We use `jitlink-check` lines in LIT tests as the primary tool for testing JITLink backends. Parsing and evaluation of the expressions is implemented in `RuntimeDyldChecker`. The `stub_addr(obj, name)` expression allows to obtain the linker-generated stub for the external symbol `name` in object file `obj`. This patch adds support for a filter parameter to select one out of many stubs. This is necessary for the AArch32 JITLink backend, which must be able to emit two different kinds of stubs depending on the instruction set state (Arm/Thumb) of the relocation site. Since the new parameter is optional, we don't have to update existing tests. Filters are regular expressions without brackets that match exactly one existing stub. Given object file `armv7.o` with two stubs for external function `ext` of kinds `armv7_abs_le` and `thumbv7_abs_le`, we get the following filter results e.g.: ``` stub_addr(armv7.o, ext, thumb) thumbv7_abs_le stub_addr(armv7.o, ext, thumbv7) thumbv7_abs_le stub_addr(armv7.o, ext, armv7_abs_le) armv7_abs_le stub_addr(armv7.o, ext, v7_.*_le) Error: "ext" has 2 candidate stubs in file "armv7.o". Please refine stub-kind filter "v7_.*_le" for disambiguation (encountered kinds are "thumbv7_abs_le", "armv7_abs_le"). stub_addr(armv7.o, ext, v8) Error: "ext" has 2 stubs in file "armv7.o", but none of them matches the stub-kind filter "v8" (all encountered kinds are "thumbv7_abs_le", "armv7_abs_le"). ```
1 parent 9eb0f86 commit 6a433d7

File tree

7 files changed

+114
-24
lines changed

7 files changed

+114
-24
lines changed

llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class RuntimeDyldChecker {
154154
using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
155155
StringRef FileName, StringRef SectionName)>;
156156
using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
157-
StringRef StubContainer, StringRef TargetName)>;
157+
StringRef StubContainer, StringRef TargetName, StringRef StubKindFilter)>;
158158
using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
159159
StringRef GOTContainer, StringRef TargetName)>;
160160

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -400,15 +400,25 @@ class RuntimeDyldCheckerExprEval {
400400
StringRef Symbol;
401401
std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
402402

403+
// Parse optional parameter to filter by stub kind
404+
StringRef KindNameFilter;
405+
if (RemainingExpr.starts_with(",")) {
406+
RemainingExpr = RemainingExpr.substr(1).ltrim();
407+
size_t ClosingBracket = RemainingExpr.find(")");
408+
KindNameFilter = RemainingExpr.substr(0, ClosingBracket);
409+
RemainingExpr = RemainingExpr.substr(ClosingBracket);
410+
}
411+
403412
if (!RemainingExpr.starts_with(")"))
404413
return std::make_pair(
405414
unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
406415
RemainingExpr = RemainingExpr.substr(1).ltrim();
407416

408417
uint64_t StubAddr;
409418
std::string ErrorMsg;
410-
std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
411-
StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr);
419+
std::tie(StubAddr, ErrorMsg) =
420+
Checker.getStubOrGOTAddrFor(StubContainerName, Symbol, KindNameFilter,
421+
PCtx.IsInsideLoad, IsStubAddr);
412422

413423
if (ErrorMsg != "")
414424
return std::make_pair(EvalResult(ErrorMsg), "");
@@ -985,11 +995,14 @@ std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
985995
}
986996

987997
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
988-
StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad,
989-
bool IsStubAddr) const {
990-
991-
auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName)
992-
: GetGOTInfo(StubContainerName, SymbolName);
998+
StringRef StubContainerName, StringRef SymbolName, StringRef StubKindFilter,
999+
bool IsInsideLoad, bool IsStubAddr) const {
1000+
1001+
assert((StubKindFilter.empty() || IsStubAddr) &&
1002+
"Kind name filter only supported for stubs");
1003+
auto StubInfo =
1004+
IsStubAddr ? GetStubInfo(StubContainerName, SymbolName, StubKindFilter)
1005+
: GetGOTInfo(StubContainerName, SymbolName);
9931006

9941007
if (!StubInfo) {
9951008
std::string ErrMsg;

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class RuntimeDyldCheckerImpl {
6464

6565
std::pair<uint64_t, std::string>
6666
getStubOrGOTAddrFor(StringRef StubContainerName, StringRef Symbol,
67-
bool IsInsideLoad, bool IsStubAddr) const;
67+
StringRef StubKindFilter, bool IsInsideLoad,
68+
bool IsStubAddr) const;
6869

6970
std::optional<uint64_t> getSectionLoadAddress(void *LocalAddr) const;
7071

llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static Error registerSymbol(LinkGraph &G, Symbol &Sym, Session::FileInfo &FI,
9191
case Stubs:
9292
return FI.registerStubEntry(G, Sym, getELFStubTarget);
9393
case AArch32Stubs:
94-
return FI.registerStubEntry(G, Sym, getELFAArch32StubTarget);
94+
return FI.registerMultiStubEntry(G, Sym, getELFAArch32StubTarget);
9595
case Other:
9696
return Error::success();
9797
}

llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,12 @@ operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
331331
OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
332332
for (auto &GOTKV : FI.GOTEntryInfos)
333333
OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
334-
for (auto &StubKV : FI.StubInfos)
335-
OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
334+
for (auto &StubKVs : FI.StubInfos) {
335+
OS << " Stubs \"" << StubKVs.first() << "\":";
336+
for (auto MemRegion : StubKVs.second)
337+
OS << " " << MemRegion;
338+
OS << "\n";
339+
}
336340
return OS;
337341
}
338342

@@ -1207,9 +1211,35 @@ Error Session::FileInfo::registerStubEntry(
12071211
auto TS = GetSymbolTarget(G, Sym.getBlock());
12081212
if (!TS)
12091213
return TS.takeError();
1210-
StubInfos[TS->getName()] = {Sym.getSymbolContent(),
1211-
Sym.getAddress().getValue(),
1212-
Sym.getTargetFlags()};
1214+
1215+
SmallVector<MemoryRegionInfo> &Entry = StubInfos[TS->getName()];
1216+
Entry.insert(Entry.begin(),
1217+
{Sym.getSymbolContent(), Sym.getAddress().getValue(),
1218+
Sym.getTargetFlags()});
1219+
return Error::success();
1220+
}
1221+
1222+
Error Session::FileInfo::registerMultiStubEntry(
1223+
LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) {
1224+
if (Sym.isSymbolZeroFill())
1225+
return make_error<StringError>("Unexpected zero-fill symbol in section " +
1226+
Sym.getBlock().getSection().getName(),
1227+
inconvertibleErrorCode());
1228+
1229+
auto Target = GetSymbolTarget(G, Sym.getBlock());
1230+
if (!Target)
1231+
return Target.takeError();
1232+
1233+
SmallVector<MemoryRegionInfo> &Entry = StubInfos[Target->getName()];
1234+
Entry.emplace_back(Sym.getSymbolContent(), Sym.getAddress().getValue(),
1235+
Sym.getTargetFlags());
1236+
1237+
// Let's keep stubs ordered by ascending address.
1238+
std::sort(Entry.begin(), Entry.end(),
1239+
[](const MemoryRegionInfo &L, const MemoryRegionInfo &R) {
1240+
return L.getTargetAddress() < R.getTargetAddress();
1241+
});
1242+
12131243
return Error::success();
12141244
}
12151245

@@ -1235,8 +1265,14 @@ Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
12351265
return SecInfoItr->second;
12361266
}
12371267

1268+
static StringRef detectStubKind(const Session::MemoryRegionInfo &Stub) {
1269+
// Implement acutal stub kind detection
1270+
return "";
1271+
}
1272+
12381273
Expected<Session::MemoryRegionInfo &>
1239-
Session::findStubInfo(StringRef FileName, StringRef TargetName) {
1274+
Session::findStubInfo(StringRef FileName, StringRef TargetName,
1275+
StringRef KindNameFilter) {
12401276
auto FI = findFileInfo(FileName);
12411277
if (!FI)
12421278
return FI.takeError();
@@ -1246,7 +1282,38 @@ Session::findStubInfo(StringRef FileName, StringRef TargetName) {
12461282
"\" registered for file \"" + FileName +
12471283
"\"",
12481284
inconvertibleErrorCode());
1249-
return StubInfoItr->second;
1285+
auto &StubsForTarget = StubInfoItr->second;
1286+
assert(!StubsForTarget.empty() && "At least 1 stub in each entry");
1287+
if (KindNameFilter.empty() && StubsForTarget.size() == 1)
1288+
return StubsForTarget[0]; // Regular single-stub match
1289+
1290+
std::string KindsStr;
1291+
SmallVector<MemoryRegionInfo *, 1> Matches;
1292+
Regex KindNameMatcher(KindNameFilter.empty() ? ".*" : KindNameFilter);
1293+
for (MemoryRegionInfo &Stub : StubsForTarget) {
1294+
StringRef Kind = detectStubKind(Stub);
1295+
if (KindNameMatcher.match(Kind))
1296+
Matches.push_back(&Stub);
1297+
KindsStr += "\"" + (Kind.empty() ? "<unknown>" : Kind.str()) + "\", ";
1298+
}
1299+
if (Matches.empty())
1300+
return make_error<StringError>(
1301+
"\"" + TargetName + "\" has " + Twine(StubsForTarget.size()) +
1302+
" stubs in file \"" + FileName +
1303+
"\", but none of them matches the stub-kind filter \"" +
1304+
KindNameFilter + "\" (all encountered kinds are " +
1305+
StringRef(KindsStr.data(), KindsStr.size() - 2) + ").",
1306+
inconvertibleErrorCode());
1307+
if (Matches.size() > 1)
1308+
return make_error<StringError>(
1309+
"\"" + TargetName + "\" has " + Twine(Matches.size()) +
1310+
" candidate stubs in file \"" + FileName +
1311+
"\". Please refine stub-kind filter \"" + KindNameFilter +
1312+
"\" for disambiguation (encountered kinds are " +
1313+
StringRef(KindsStr.data(), KindsStr.size() - 2) + ").",
1314+
inconvertibleErrorCode());
1315+
1316+
return *Matches[0];
12501317
}
12511318

12521319
Expected<Session::MemoryRegionInfo &>
@@ -2015,8 +2082,9 @@ static Error runChecks(Session &S, Triple TT, SubtargetFeatures Features) {
20152082
return S.findSectionInfo(FileName, SectionName);
20162083
};
20172084

2018-
auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
2019-
return S.findStubInfo(FileName, SectionName);
2085+
auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName,
2086+
StringRef KindNameFilter) {
2087+
return S.findStubInfo(FileName, SectionName, KindNameFilter);
20202088
};
20212089

20222090
auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {

llvm/tools/llvm-jitlink/llvm-jitlink.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct Session {
4949

5050
struct FileInfo {
5151
StringMap<MemoryRegionInfo> SectionInfos;
52-
StringMap<MemoryRegionInfo> StubInfos;
52+
StringMap<SmallVector<MemoryRegionInfo, 1>> StubInfos;
5353
StringMap<MemoryRegionInfo> GOTEntryInfos;
5454

5555
using Symbol = jitlink::Symbol;
@@ -61,6 +61,8 @@ struct Session {
6161
GetSymbolTargetFunction GetSymbolTarget);
6262
Error registerStubEntry(LinkGraph &G, Symbol &Sym,
6363
GetSymbolTargetFunction GetSymbolTarget);
64+
Error registerMultiStubEntry(LinkGraph &G, Symbol &Sym,
65+
GetSymbolTargetFunction GetSymbolTarget);
6466
};
6567

6668
using DynLibJDMap = std::map<std::string, orc::JITDylib *>;
@@ -74,7 +76,8 @@ struct Session {
7476
Expected<MemoryRegionInfo &> findSectionInfo(StringRef FileName,
7577
StringRef SectionName);
7678
Expected<MemoryRegionInfo &> findStubInfo(StringRef FileName,
77-
StringRef TargetName);
79+
StringRef TargetName,
80+
StringRef KindNameFilter);
7881
Expected<MemoryRegionInfo &> findGOTEntryInfo(StringRef FileName,
7982
StringRef TargetName);
8083

llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,8 @@ static int linkAndVerify() {
926926
};
927927

928928
auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,
929-
StringRef SymbolName)
929+
StringRef SymbolName,
930+
StringRef KindNameFilter)
930931
-> Expected<RuntimeDyldChecker::MemoryRegionInfo> {
931932
if (!StubMap.count(StubContainer))
932933
return make_error<StringError>("Stub container not found: " +
@@ -947,6 +948,11 @@ static int linkAndVerify() {
947948
return StubMemInfo;
948949
};
949950

951+
auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer,
952+
StringRef SymbolName) {
953+
return GetStubInfo(StubContainer, SymbolName, "");
954+
};
955+
950956
// We will initialize this below once we have the first object file and can
951957
// know the endianness.
952958
std::unique_ptr<RuntimeDyldChecker> Checker;
@@ -977,8 +983,7 @@ static int linkAndVerify() {
977983

978984
if (!Checker)
979985
Checker = std::make_unique<RuntimeDyldChecker>(
980-
IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo,
981-
GetStubInfo,
986+
IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
982987
Obj.isLittleEndian() ? llvm::endianness::little
983988
: llvm::endianness::big,
984989
TheTriple, MCPU, SubtargetFeatures(), dbgs());

0 commit comments

Comments
 (0)