diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -38,6 +38,7 @@ bool staticLink = false; bool isPic = false; bool headerPadMaxInstallNames = false; + bool printWhyLoad = false; bool searchDylibsFirst = false; bool saveTemps = false; uint32_t headerPad; diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -19,6 +19,7 @@ namespace macho { class DylibFile; +class InputFile; class MachOOptTable : public llvm::opt::OptTable { public: @@ -45,6 +46,8 @@ uint32_t getModTime(llvm::StringRef path); +void printWhyLoad(StringRef reason, const InputFile *); + } // namespace macho } // namespace lld diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -275,6 +275,8 @@ for (const ArchiveMember &member : getArchiveMembers(*buffer)) { inputFiles.push_back( make(member.mbref, member.modTime, path)); + printWhyLoad((forceLoadArchive ? "-force_load" : "-all_load"), + inputFiles.back()); } } } else if (config->forceLoadObjC) { @@ -291,6 +293,7 @@ if (hasObjCSection(member.mbref)) { inputFiles.push_back( make(member.mbref, member.modTime, path)); + printWhyLoad("-ObjC", inputFiles.back()); } } } @@ -637,6 +640,7 @@ config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32); config->headerPadMaxInstallNames = args.hasArg(OPT_headerpad_max_install_names); + config->printWhyLoad = args.hasArg(OPT_why_load); config->outputType = getOutputType(args); config->runtimePaths = args::getStrings(args, OPT_rpath); config->allLoad = args.hasArg(OPT_all_load); diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Driver.h" +#include "Config.h" #include "InputFiles.h" #include "lld/Common/Args.h" @@ -185,3 +186,10 @@ warn("failed to get modification time of " + path); return 0; } + +void macho::printWhyLoad(StringRef reason, const InputFile *f) { + if (!config->printWhyLoad) + return; + lld::outs() << reason << " forced load of " << toString(f) + << '\n'; +} diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -621,6 +621,10 @@ auto file = make(mb, modTime, getName()); + // ld64 doesn't demangle sym here even with -demangle. Match that, so + // intentionally no call to toMachOString() here. + printWhyLoad(sym.getName(), file); + symbols.insert(symbols.end(), file->symbols.begin(), file->symbols.end()); subsections.insert(subsections.end(), file->subsections.begin(), file->subsections.end()); diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -426,8 +426,7 @@ def grp_introspect : OptionGroup<"introspect">, HelpText<"INTROSPECTING THE LINKER">; def why_load : Flag<["-"], "why_load">, - HelpText<"Log the symbol that compels loading of each object file from a static library">, - Flags<[HelpHidden]>, + HelpText<"Log why each object file is loaded from a static library">, Group; def whyload : Flag<["-"], "whyload">, Alias, diff --git a/lld/test/MachO/why-load.s b/lld/test/MachO/why-load.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/why-load.s @@ -0,0 +1,83 @@ +# REQUIRES: x86 +# RUN: rm -rf %t +# RUN: split-file %s %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/objc.o %t/objc.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/foo.o %t/foo.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/bar.o %t/bar.s +# RUN: llvm-ar csr %t/lib.a %t/objc.o %t/foo.o %t/bar.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/main.o %t/main.s + +# The first line checks that we never demangle symbols in -why_load output. +# RUN: %lld %t/main.o %t/lib.a -o /dev/null -why_load -demangle | \ +# RUN: FileCheck %s --check-prefix=WHY +# RUN: %lld %t/main.o -force_load %t/lib.a -o /dev/null -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYFORCE +# RUN: %lld %t/main.o %t/lib.a -o /dev/null -all_load -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYALL +# RUN: %lld %t/main.o -force_load %t/lib.a -o /dev/null -all_load -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYALLFORCE + +# RUN: %lld %t/main.o %t/lib.a -o /dev/null -ObjC -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYOBJC +# RUN: %lld %t/main.o -force_load %t/lib.a -o /dev/null -ObjC -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYOBJCFORCE +# RUN: %lld %t/main.o %t/lib.a -o /dev/null -ObjC -all_load -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYOBJCALL +# RUN: %lld %t/main.o -force_load %t/lib.a -o /dev/null -ObjC -all_load -why_load | \ +# RUN: FileCheck %s --check-prefix=WHYOBJCALLFORCE + +# WHY-DAG: _bar forced load of lib.a(bar.o) +# WHY-DAG: __Z3foo forced load of lib.a(foo.o) +# WHY-NOT: {{.*}} forced load of lib.a(objc.o) + +# WHYFORCE-DAG: -force_load forced load of lib.a(bar.o) +# WHYFORCE-DAG: -force_load forced load of lib.a(foo.o) +# WHYFORCE-DAG: -force_load forced load of lib.a(objc.o) + +# WHYALL-DAG: -all_load forced load of lib.a(bar.o) +# WHYALL-DAG: -all_load forced load of lib.a(foo.o) +# WHYALL-DAG: -all_load forced load of lib.a(objc.o) + +# WHYALLFORCE-DAG: -force_load forced load of lib.a(bar.o) +# WHYALLFORCE-DAG: -force_load forced load of lib.a(foo.o) +# WHYALLFORCE-DAG: -force_load forced load of lib.a(objc.o) + +# WHYOBJC-DAG: _bar forced load of lib.a(bar.o) +# WHYOBJC-DAG: __Z3foo forced load of lib.a(foo.o) +# WHYOBJC-DAG: -ObjC forced load of lib.a(objc.o) + +# WHYOBJCFORCE-DAG: -force_load forced load of lib.a(bar.o) +# WHYOBJCFORCE-DAG: -force_load forced load of lib.a(foo.o) +# WHYOBJCFORCE-DAG: -force_load forced load of lib.a(objc.o) + +# WHYOBJCALL-DAG: -all_load forced load of lib.a(bar.o) +# WHYOBJCALL-DAG: -all_load forced load of lib.a(foo.o) +# WHYOBJCALL-DAG: -all_load forced load of lib.a(objc.o) + +# WHYOBJCALLFORCE-DAG: -force_load forced load of lib.a(bar.o) +# WHYOBJCALLFORCE-DAG: -force_load forced load of lib.a(foo.o) +# WHYOBJCALLFORCE-DAG: -force_load forced load of lib.a(objc.o) + +#--- objc.s +.section __DATA,__objc_catlist +.quad 0x1234 + +#--- foo.s +.globl __Z3foo +__Z3foo: + ret + +#--- bar.s +.globl _bar +_bar: + callq __Z3foo + ret + +#--- main.s +.globl _main +_main: + callq _bar + callq __Z3foo + ret