Teach llvm-jitlink to support archives in inputs files and -load_hidden

Similar to the ld64 command-line options. These use the same underlying
mechanisms as -l and -hidden-l, but allow specifying an absolute path to
the archive. This is often more convenient for a one-off, or when adding
a new search path could change how existing -l options are resolved.

Differential Revision: https://reviews.llvm.org/D117360
This commit is contained in:
Ben Langmuir 2022-01-14 12:07:25 -08:00
parent 258cd02c6a
commit ca2353ce5a
3 changed files with 75 additions and 20 deletions

View File

@ -6,6 +6,8 @@
# RUN: -o %t/MachO_archive_load_hidden_support.o %s
# RUN: llvm-jitlink -noexec %t/MachO_archive_load_hidden_support.o \
# RUN: -L%t -hidden-lExtraDef
# RUN: llvm-jitlink -noexec %t/MachO_archive_load_hidden_support.o \
# RUN: -load_hidden %t/libExtraDef.a
#
# Expect this test to succeed -- ExtraDef should be hidden, but visible to
# ExtraDefRef as they're linked in the same JITDylib. This tests that we're

View File

@ -5,6 +5,7 @@
# RUN: llvm-mc -triple x86_64-apple-macosx10.9 -filetype=obj \
# RUN: -o %t/MachO_archive_support.o %s
# RUN: llvm-jitlink -noexec %t/MachO_archive_support.o -lFoo -jd Foo -L%t -lExtraDef
# RUN: llvm-jitlink -noexec %t/MachO_archive_support.o -lFoo -jd Foo %t/libExtraDef.a
#
# Test that archives can be loaded and referenced from other JITDylibs.

View File

@ -82,9 +82,16 @@ static cl::list<std::string>
cl::desc("Link against library X in the library search paths"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string> LibrariesHidden(
"hidden-l", cl::desc("Link against library X in the library search paths"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string>
LibrariesHidden("hidden-l",
cl::desc("Link against library X in the library search "
"paths with hidden visibility"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string>
LoadHidden("load_hidden",
cl::desc("Link against library X with hidden visibility"),
cl::cat(JITLinkCategory));
static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
cl::init(false), cl::cat(JITLinkCategory));
@ -1403,6 +1410,8 @@ static Error addObjects(Session &S,
unsigned InputFileArgIdx =
InputFiles.getPosition(InputFileItr - InputFiles.begin());
const std::string &InputFile = *InputFileItr;
if (StringRef(InputFile).endswith(".a"))
continue;
auto &JD = *std::prev(IdxToJD.lower_bound(InputFileArgIdx))->second;
LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
<< "\" to " << JD.getName() << "\n";);
@ -1474,14 +1483,41 @@ static Error addLibraries(Session &S,
}
});
// 2. Collect library loads from -lx, -hidden-lx.
// 2. Collect library loads
struct LibraryLoad {
StringRef LibName;
bool IsPath = false;
unsigned Position;
StringRef *CandidateExtensions;
enum { Standard, Hidden } Modifier;
};
std::vector<LibraryLoad> LibraryLoads;
// Add archive files from the inputs to LibraryLoads.
for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
InputFileItr != InputFileEnd; ++InputFileItr) {
StringRef InputFile = *InputFileItr;
if (!InputFile.endswith(".a"))
continue;
LibraryLoad LL;
LL.LibName = InputFile;
LL.IsPath = true;
LL.Position = InputFiles.getPosition(InputFileItr - InputFiles.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Standard;
LibraryLoads.push_back(std::move(LL));
}
// Add -load_hidden arguments to LibraryLoads.
for (auto LibItr = LoadHidden.begin(), LibEnd = LoadHidden.end();
LibItr != LibEnd; ++LibItr) {
LibraryLoad LL;
LL.LibName = *LibItr;
LL.IsPath = true;
LL.Position = LoadHidden.getPosition(LibItr - LoadHidden.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Hidden;
LibraryLoads.push_back(std::move(LL));
}
StringRef StandardExtensions[] = {".so", ".dylib", ".a"};
StringRef ArchiveExtensionsOnly[] = {".a"};
@ -1511,7 +1547,7 @@ static Error addLibraries(Session &S,
// If there are any load-<modified> options then turn on flag overrides
// to avoid flag mismatch errors.
if (!LibrariesHidden.empty())
if (!LibrariesHidden.empty() || !LoadHidden.empty())
S.ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
// Sort library loads by position in the argument list.
@ -1520,6 +1556,24 @@ static Error addLibraries(Session &S,
});
// 3. Process library loads.
auto AddArchive = [&](const char *Path, const LibraryLoad &LL)
-> Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> {
unique_function<Expected<MaterializationUnit::Interface>(
ExecutionSession & ES, MemoryBufferRef ObjBuffer)>
GetObjFileInterface;
switch (LL.Modifier) {
case LibraryLoad::Standard:
GetObjFileInterface = getObjectFileInterface;
break;
case LibraryLoad::Hidden:
GetObjFileInterface = getObjectFileInterfaceHidden;
break;
}
return StaticLibraryDefinitionGenerator::Load(
S.ObjLayer, Path, S.ES.getExecutorProcessControl().getTargetTriple(),
std::move(GetObjFileInterface));
};
for (auto &LL : LibraryLoads) {
bool LibFound = false;
auto &JD = *std::prev(IdxToJD.lower_bound(LL.Position))->second;
@ -1530,6 +1584,18 @@ static Error addLibraries(Session &S,
continue;
}
if (LL.IsPath) {
auto G = AddArchive(LL.LibName.str().c_str(), LL);
if (!G)
return createFileError(LL.LibName, G.takeError());
JD.addGenerator(std::move(*G));
LLVM_DEBUG({
dbgs() << "Adding generator for static library " << LL.LibName << " to "
<< JD.getName() << "\n";
});
continue;
}
// Otherwise look through the search paths.
auto JDSearchPathsItr = JDSearchPaths.find(&JD);
if (JDSearchPathsItr != JDSearchPaths.end()) {
@ -1583,21 +1649,7 @@ static Error addLibraries(Session &S,
}
case file_magic::archive:
case file_magic::macho_universal_binary: {
unique_function<Expected<MaterializationUnit::Interface>(
ExecutionSession & ES, MemoryBufferRef ObjBuffer)>
GetObjFileInterface;
switch (LL.Modifier) {
case LibraryLoad::Standard:
GetObjFileInterface = getObjectFileInterface;
break;
case LibraryLoad::Hidden:
GetObjFileInterface = getObjectFileInterfaceHidden;
break;
}
auto G = StaticLibraryDefinitionGenerator::Load(
S.ObjLayer, LibPath.data(),
S.ES.getExecutorProcessControl().getTargetTriple(),
std::move(GetObjFileInterface));
auto G = AddArchive(LibPath.data(), LL);
if (!G)
return G.takeError();
JD.addGenerator(std::move(*G));