forked from OSchip/llvm-project
[lld-macho] Allow linking with ABI compatible architectures
Linking fails when targeting `x86_64-apple-darwin` for runtimes. The issue is that LLD strictly assumes the target architecture be present in the tbd files (which isn't always true). For example, when targeting `x86_64h`, it should work with `x86_64` because they are ABI compatible. This is also inline with what ld64 does. An environment variable (which ld64 also supports) is also added to preserve the existing behavior of strict architecture matching. Reviewed By: #lld-macho, int3 Differential Revision: https://reviews.llvm.org/D130683
This commit is contained in:
parent
520d29f381
commit
f030132c72
|
@ -131,6 +131,7 @@ struct Configuration {
|
|||
bool omitDebugInfo = false;
|
||||
bool warnDylibInstallName = false;
|
||||
bool ignoreOptimizationHints = false;
|
||||
bool forceExactCpuSubtypeMatch = false;
|
||||
uint32_t headerPad;
|
||||
uint32_t dylibCompatibilityVersion = 0;
|
||||
uint32_t dylibCurrentVersion = 0;
|
||||
|
|
|
@ -1399,6 +1399,8 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
|
|||
config->callGraphProfileSort = args.hasFlag(
|
||||
OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
|
||||
config->printSymbolOrder = args.getLastArgValue(OPT_print_symbol_order);
|
||||
config->forceExactCpuSubtypeMatch =
|
||||
getenv("LD_DYLIB_CPU_SUBTYPES_MUST_MATCH");
|
||||
|
||||
for (const Arg *arg : args.filtered(OPT_alias)) {
|
||||
config->aliasedSymbols.push_back(
|
||||
|
|
|
@ -1067,8 +1067,11 @@ template <class LP> void ObjFile::parse() {
|
|||
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
|
||||
auto *hdr = reinterpret_cast<const Header *>(mb.getBufferStart());
|
||||
|
||||
Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype);
|
||||
if (arch != config->arch()) {
|
||||
uint32_t cpuType;
|
||||
std::tie(cpuType, std::ignore) = getCPUTypeFromArchitecture(config->arch());
|
||||
if (hdr->cputype != cpuType) {
|
||||
Architecture arch =
|
||||
getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype);
|
||||
auto msg = config->errorForArchMismatch
|
||||
? static_cast<void (*)(const Twine &)>(error)
|
||||
: warn;
|
||||
|
@ -1865,6 +1868,36 @@ static bool skipPlatformCheckForCatalyst(const InterfaceFile &interface,
|
|||
MachO::Target(config->arch(), PLATFORM_MACOS));
|
||||
}
|
||||
|
||||
static bool isArchABICompatible(ArchitectureSet archSet,
|
||||
Architecture targetArch) {
|
||||
uint32_t cpuType;
|
||||
uint32_t targetCpuType;
|
||||
std::tie(targetCpuType, std::ignore) = getCPUTypeFromArchitecture(targetArch);
|
||||
|
||||
return llvm::any_of(archSet, [&](const auto &p) {
|
||||
std::tie(cpuType, std::ignore) = getCPUTypeFromArchitecture(p);
|
||||
return cpuType == targetCpuType;
|
||||
});
|
||||
}
|
||||
|
||||
static bool isTargetPlatformArchCompatible(
|
||||
InterfaceFile::const_target_range interfaceTargets, Target target) {
|
||||
if (is_contained(interfaceTargets, target))
|
||||
return true;
|
||||
|
||||
if (config->forceExactCpuSubtypeMatch)
|
||||
return false;
|
||||
|
||||
ArchitectureSet archSet;
|
||||
for (const auto &p : interfaceTargets)
|
||||
if (p.Platform == target.Platform)
|
||||
archSet.set(p.Arch);
|
||||
if (archSet.empty())
|
||||
return false;
|
||||
|
||||
return isArchABICompatible(archSet, target.Arch);
|
||||
}
|
||||
|
||||
DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
|
||||
bool isBundleLoader, bool explicitlyLinked)
|
||||
: InputFile(DylibKind, interface), refState(RefState::Unreferenced),
|
||||
|
@ -1884,7 +1917,8 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
|
|||
inputFiles.insert(this);
|
||||
|
||||
if (!is_contained(skipPlatformChecks, installName) &&
|
||||
!is_contained(interface.targets(), config->platformInfo.target) &&
|
||||
!isTargetPlatformArchCompatible(interface.targets(),
|
||||
config->platformInfo.target) &&
|
||||
!skipPlatformCheckForCatalyst(interface, explicitlyLinked)) {
|
||||
error(toString(this) + " is incompatible with " +
|
||||
std::string(config->platformInfo.target));
|
||||
|
@ -1907,7 +1941,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
|
|||
std::vector<const llvm::MachO::Symbol *> normalSymbols;
|
||||
normalSymbols.reserve(interface.symbolsCount());
|
||||
for (const auto *symbol : interface.symbols()) {
|
||||
if (!symbol->getArchitectures().has(config->arch()))
|
||||
if (!isArchABICompatible(symbol->getArchitectures(), config->arch()))
|
||||
continue;
|
||||
if (handleLDSymbol(symbol->getName()))
|
||||
continue;
|
||||
|
@ -1950,7 +1984,7 @@ void DylibFile::parseReexports(const InterfaceFile &interface) {
|
|||
for (const InterfaceFileRef &intfRef : interface.reexportedLibraries()) {
|
||||
InterfaceFile::const_target_range targets = intfRef.targets();
|
||||
if (is_contained(skipPlatformChecks, intfRef.getInstallName()) ||
|
||||
is_contained(targets, config->platformInfo.target))
|
||||
isTargetPlatformArchCompatible(targets, config->platformInfo.target))
|
||||
loadReexport(intfRef.getInstallName(), exportingFile, topLevel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,18 @@
|
|||
# RUN: %lld -o %t/test -lSystem -lc++ -framework CoreFoundation %t/libNested.tbd %t/test.o
|
||||
# RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/test | FileCheck %s
|
||||
|
||||
## Targeting an arch not listed in the tbd should fallback to an ABI compatible arch
|
||||
# RUN: %lld -arch x86_64h -o %t/test-compat -lSystem -lc++ -framework CoreFoundation %t/libNested.tbd %t/test.o
|
||||
# RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/test-compat | FileCheck %s
|
||||
|
||||
## Setting LD_DYLIB_CPU_SUBTYPES_MUST_MATCH forces exact target arch match.
|
||||
# RUN: env LD_DYLIB_CPU_SUBTYPES_MUST_MATCH=1 not %lld -arch x86_64h -o /dev/null -lSystem -lc++ -framework \
|
||||
# RUN: CoreFoundation %t/libNested.tbd %t/test.o 2>&1 | FileCheck %s -check-prefix=INCOMPATIBLE
|
||||
|
||||
# INCOMPATIBLE: error: {{.*}}libSystem.tbd(/usr/lib/libSystem.dylib) is incompatible with x86_64h (macOS)
|
||||
# INCOMPATIBLE-NEXT: error: {{.*}}libc++.tbd(/usr/lib/libc++.dylib) is incompatible with x86_64h (macOS)
|
||||
# INCOMPATIBLE-NEXT: error: {{.*}}CoreFoundation.tbd(/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation) is incompatible with x86_64h (macOS)
|
||||
|
||||
## libReexportSystem.tbd tests that we can reference symbols from a 2nd-level
|
||||
## tapi document, re-exported by a top-level tapi document, which itself is
|
||||
## re-exported by another top-level tapi document.
|
||||
|
|
Loading…
Reference in New Issue