[lld-macho] -all_load and -ObjC should not affect LC_LINKER_OPTION flags

In particular, they should not cause archives to be eagerly loaded. This
matches ld64's behavior.

Fixes PR52246.

Reviewed By: #lld-macho, thakis

Differential Revision: https://reviews.llvm.org/D112756
This commit is contained in:
Jez Ng 2021-10-29 11:00:16 -04:00
parent a271f2410f
commit 6c2f26a159
3 changed files with 63 additions and 28 deletions

View File

@ -198,6 +198,13 @@ struct SymbolPriorityEntry {
llvm::DenseMap<llvm::StringRef, size_t> objectFiles;
};
// Whether to force-load an archive.
enum class ForceLoad {
Default, // Apply -all_load or -ObjC behaviors if those flags are enabled
Yes, // Always load the archive, regardless of other flags
No, // Never load the archive, regardless of other flags
};
extern Configuration *config;
} // namespace macho

View File

@ -226,7 +226,7 @@ static llvm::CachePruningPolicy getLTOCachePolicy(InputArgList &args) {
static DenseMap<StringRef, ArchiveFile *> loadedArchives;
static InputFile *addFile(StringRef path, bool forceLoadArchive,
static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive,
bool isExplicit = true, bool isBundleLoader = false) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
@ -253,11 +253,13 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
error(path + ": archive has no index; run ranlib to add one");
auto *file = make<ArchiveFile>(std::move(archive));
if (config->allLoad || forceLoadArchive) {
if ((forceLoadArchive == ForceLoad::Default && config->allLoad) ||
forceLoadArchive == ForceLoad::Yes) {
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
Error e = Error::success();
for (const object::Archive::Child &c : file->getArchive().children(e)) {
StringRef reason = forceLoadArchive ? "-force_load" : "-all_load";
StringRef reason =
forceLoadArchive == ForceLoad::Yes ? "-force_load" : "-all_load";
if (Error e = file->fetch(c, reason))
error(toString(file) + ": " + reason +
" failed to load archive member: " + toString(std::move(e)));
@ -266,7 +268,8 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
error(toString(file) +
": Archive::children failed: " + toString(std::move(e)));
}
} else if (config->forceLoadObjC) {
} else if (forceLoadArchive == ForceLoad::Default &&
config->forceLoadObjC) {
for (const object::Archive::Symbol &sym : file->getArchive().symbols())
if (sym.getName().startswith(objc::klass))
file->fetch(sym);
@ -331,10 +334,11 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
}
static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
bool isReexport, bool isExplicit, bool forceLoad) {
bool isReexport, bool isExplicit,
ForceLoad forceLoadArchive) {
if (Optional<StringRef> path = findLibrary(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(*path, forceLoad, isExplicit))) {
addFile(*path, forceLoadArchive, isExplicit))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
@ -350,10 +354,11 @@ static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
}
static void addFramework(StringRef name, bool isNeeded, bool isWeak,
bool isReexport, bool isExplicit) {
bool isReexport, bool isExplicit,
ForceLoad forceLoadArchive) {
if (Optional<StringRef> path = findFramework(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(*path, /*forceLoadArchive=*/false, isExplicit))) {
addFile(*path, forceLoadArchive, isExplicit))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
@ -392,15 +397,16 @@ void macho::parseLCLinkerOption(InputFile *f, unsigned argc, StringRef data) {
switch (arg->getOption().getID()) {
case OPT_l: {
StringRef name = arg->getValue();
bool forceLoad =
config->forceLoadSwift ? name.startswith("swift") : false;
ForceLoad forceLoadArchive =
config->forceLoadSwift && name.startswith("swift") ? ForceLoad::Yes
: ForceLoad::No;
addLibrary(name, /*isNeeded=*/false, /*isWeak=*/false,
/*isReexport=*/false, /*isExplicit=*/false, forceLoad);
/*isReexport=*/false, /*isExplicit=*/false, forceLoadArchive);
break;
}
case OPT_framework:
addFramework(arg->getValue(), /*isNeeded=*/false, /*isWeak=*/false,
/*isReexport=*/false, /*isExplicit=*/false);
/*isReexport=*/false, /*isExplicit=*/false, ForceLoad::No);
break;
default:
error(arg->getSpelling() + " is not allowed in LC_LINKER_OPTION");
@ -414,7 +420,7 @@ static void addFileList(StringRef path) {
return;
MemoryBufferRef mbref = *buffer;
for (StringRef path : args::getLines(mbref))
addFile(rerootPath(path), /*forceLoadArchive=*/false);
addFile(rerootPath(path), ForceLoad::Default);
}
// An order file has one entry per line, in the following format:
@ -947,30 +953,30 @@ static void createFiles(const InputArgList &args) {
switch (opt.getID()) {
case OPT_INPUT:
addFile(rerootPath(arg->getValue()), /*forceLoadArchive=*/false);
addFile(rerootPath(arg->getValue()), ForceLoad::Default);
break;
case OPT_needed_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(rerootPath(arg->getValue()), false)))
addFile(rerootPath(arg->getValue()), ForceLoad::Default)))
dylibFile->forceNeeded = true;
break;
case OPT_reexport_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(
rerootPath(arg->getValue()), /*forceLoadArchive=*/false))) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(rerootPath(arg->getValue()), ForceLoad::Default))) {
config->hasReexports = true;
dylibFile->reexport = true;
}
break;
case OPT_weak_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(rerootPath(arg->getValue()), /*forceLoadArchive=*/false)))
addFile(rerootPath(arg->getValue()), ForceLoad::Default)))
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
addFileList(arg->getValue());
break;
case OPT_force_load:
addFile(rerootPath(arg->getValue()), /*forceLoadArchive=*/true);
addFile(rerootPath(arg->getValue()), ForceLoad::Yes);
break;
case OPT_l:
case OPT_needed_l:
@ -978,7 +984,7 @@ static void createFiles(const InputArgList &args) {
case OPT_weak_l:
addLibrary(arg->getValue(), opt.getID() == OPT_needed_l,
opt.getID() == OPT_weak_l, opt.getID() == OPT_reexport_l,
/*isExplicit=*/true, /*forceLoad=*/false);
/*isExplicit=*/true, ForceLoad::Default);
break;
case OPT_framework:
case OPT_needed_framework:
@ -986,7 +992,8 @@ static void createFiles(const InputArgList &args) {
case OPT_weak_framework:
addFramework(arg->getValue(), opt.getID() == OPT_needed_framework,
opt.getID() == OPT_weak_framework,
opt.getID() == OPT_reexport_framework, /*isExplicit=*/true);
opt.getID() == OPT_reexport_framework, /*isExplicit=*/true,
ForceLoad::Default);
break;
default:
break;
@ -1175,7 +1182,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
if (const Arg *arg = args.getLastArg(OPT_bundle_loader)) {
if (config->outputType != MH_BUNDLE)
error("-bundle_loader can only be used with MachO bundle output");
addFile(arg->getValue(), /*forceLoadArchive=*/false, /*isExplicit=*/false,
addFile(arg->getValue(), ForceLoad::Default, /*isExplicit=*/false,
/*isBundleLoader=*/true);
}
if (const Arg *arg = args.getLastArg(OPT_umbrella)) {

View File

@ -58,9 +58,24 @@
;; actual archive at Foo.framework/Versions/Current, but we skip that here so
;; that this test can run on Windows.
; RUN: llvm-ar rcs %t/Foo.framework/Foo %t/foo.o
; RUN: llc %t/objfile1.ll -o %t/objfile1.o -filetype=obj
; RUN: llc %t/load-framework-foo.ll -o %t/load-framework-foo.o -filetype=obj
; RUN: llc %t/main.ll -o %t/main.o -filetype=obj
; RUN: %lld %t/objfile1.o %t/main.o -o /dev/null -F%t
; RUN: %lld %t/load-framework-foo.o %t/main.o -o %t/main -F%t
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS
;; Make sure -all_load and -ObjC have no effect on libraries loaded via
;; LC_LINKER_OPTION flags.
; RUN: llc %t/load-library-foo.ll -o %t/load-library-foo.o -filetype=obj
; RUN: llvm-ar rcs %t/libfoo.a %t/foo.o
; RUN: %lld -all_load -ObjC %t/load-framework-foo.o %t/load-library-foo.o \
; RUN: %t/main.o -o %t/main -F%t -L%t
; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS
;; Note that _OBJC_CLASS_$_TestClass is *not* included here.
; SYMS: SYMBOL TABLE:
; SYMS-NEXT: g F __TEXT,__text _main
; SYMS-NEXT: g F __TEXT,__text __mh_execute_header
; SYMS-EMPTY:
;--- framework.ll
target triple = "x86_64-apple-macosx10.15.0"
@ -105,13 +120,20 @@ define void @main() {
ret void
}
;--- objfile1.ll
;--- load-framework-foo.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
!0 = !{!"-framework", !"Foo"}
!llvm.linker.options = !{!0}
;--- load-library-foo.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
!0 = !{!"-lfoo"}
!llvm.linker.options = !{!0}
;--- main.ll
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
@ -127,6 +149,5 @@ define void @main() {
target triple = "x86_64-apple-macosx10.15.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
define void @foo() {
ret void
}
%struct._class_t = type {}
@"OBJC_CLASS_$_TestClass" = global %struct._class_t {}, section "__DATA, __objc_data", align 8