diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -198,6 +198,13 @@ llvm::DenseMap 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 diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -226,7 +226,7 @@ static DenseMap loadedArchives; -static InputFile *addFile(StringRef path, bool forceLoadArchive, +static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive, bool isExplicit = true, bool isBundleLoader = false) { Optional buffer = readFile(path); if (!buffer) @@ -253,11 +253,13 @@ error(path + ": archive has no index; run ranlib to add one"); auto *file = make(std::move(archive)); - if (config->allLoad || forceLoadArchive) { + if ((forceLoadArchive == ForceLoad::Default && config->allLoad) || + forceLoadArchive == ForceLoad::Yes) { if (Optional 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 @@ 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 void addLibrary(StringRef name, bool isNeeded, bool isWeak, - bool isReexport, bool isExplicit, bool forceLoad) { + bool isReexport, bool isExplicit, + ForceLoad forceLoadArchive) { if (Optional path = findLibrary(name)) { if (auto *dylibFile = dyn_cast_or_null( - addFile(*path, forceLoad, isExplicit))) { + addFile(*path, forceLoadArchive, isExplicit))) { if (isNeeded) dylibFile->forceNeeded = true; if (isWeak) @@ -350,10 +354,11 @@ } static void addFramework(StringRef name, bool isNeeded, bool isWeak, - bool isReexport, bool isExplicit) { + bool isReexport, bool isExplicit, + ForceLoad forceLoadArchive) { if (Optional path = findFramework(name)) { if (auto *dylibFile = dyn_cast_or_null( - addFile(*path, /*forceLoadArchive=*/false, isExplicit))) { + addFile(*path, forceLoadArchive, isExplicit))) { if (isNeeded) dylibFile->forceNeeded = true; if (isWeak) @@ -392,15 +397,16 @@ 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 @@ 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 @@ 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( - 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(addFile( - rerootPath(arg->getValue()), /*forceLoadArchive=*/false))) { + if (auto *dylibFile = dyn_cast_or_null( + addFile(rerootPath(arg->getValue()), ForceLoad::Default))) { config->hasReexports = true; dylibFile->reexport = true; } break; case OPT_weak_library: if (auto *dylibFile = dyn_cast_or_null( - 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 @@ 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 @@ 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 @@ 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)) { diff --git a/lld/test/MachO/lc-linker-option.ll b/lld/test/MachO/lc-linker-option.ll --- a/lld/test/MachO/lc-linker-option.ll +++ b/lld/test/MachO/lc-linker-option.ll @@ -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 @@ 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 @@ 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