Skip to content

Commit

Permalink
[mac/lld] Implement -why_load
Browse files Browse the repository at this point in the history
This is useful for debugging why lld loads .o files it shouldn't load.
It's also useful for users of lld -- I've used ld64's version of this a
few times.

Differential Revision: https://reviews.llvm.org/D92496
  • Loading branch information
nico committed Dec 2, 2020
1 parent 86f59de commit 542d3b6
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 2 deletions.
1 change: 1 addition & 0 deletions lld/MachO/Config.h
Expand Up @@ -38,6 +38,7 @@ struct Configuration {
bool staticLink = false;
bool isPic = false;
bool headerPadMaxInstallNames = false;
bool printWhyLoad = false;
bool searchDylibsFirst = false;
bool saveTemps = false;
uint32_t headerPad;
Expand Down
4 changes: 4 additions & 0 deletions lld/MachO/Driver.cpp
Expand Up @@ -275,6 +275,8 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive) {
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
inputFiles.push_back(
make<ObjFile>(member.mbref, member.modTime, path));
printWhyLoad((forceLoadArchive ? "-force_load" : "-all_load"),
inputFiles.back());
}
}
} else if (config->forceLoadObjC) {
Expand All @@ -291,6 +293,7 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive) {
if (hasObjCSection(member.mbref)) {
inputFiles.push_back(
make<ObjFile>(member.mbref, member.modTime, path));
printWhyLoad("-ObjC", inputFiles.back());
}
}
}
Expand Down Expand Up @@ -637,6 +640,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
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);
Expand Down
3 changes: 3 additions & 0 deletions lld/MachO/Driver.h
Expand Up @@ -19,6 +19,7 @@ namespace lld {
namespace macho {

class DylibFile;
class InputFile;

class MachOOptTable : public llvm::opt::OptTable {
public:
Expand All @@ -45,6 +46,8 @@ llvm::Optional<DylibFile *> makeDylibFromTAPI(llvm::MemoryBufferRef mbref,

uint32_t getModTime(llvm::StringRef path);

void printWhyLoad(StringRef reason, const InputFile *);

} // namespace macho
} // namespace lld

Expand Down
8 changes: 8 additions & 0 deletions lld/MachO/DriverUtils.cpp
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Driver.h"
#include "Config.h"
#include "InputFiles.h"

#include "lld/Common/Args.h"
Expand Down Expand Up @@ -185,3 +186,10 @@ uint32_t macho::getModTime(StringRef path) {
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';
}
4 changes: 4 additions & 0 deletions lld/MachO/InputFiles.cpp
Expand Up @@ -621,6 +621,10 @@ void ArchiveFile::fetch(const object::Archive::Symbol &sym) {

auto file = make<ObjFile>(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());
Expand Down
3 changes: 1 addition & 2 deletions lld/MachO/Options.td
Expand Up @@ -426,8 +426,7 @@ def commons : Separate<["-"], "commons">,
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<grp_introspect>;
def whyload : Flag<["-"], "whyload">,
Alias<why_load>,
Expand Down
83 changes: 83 additions & 0 deletions 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

0 comments on commit 542d3b6

Please sign in to comment.