diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -43,8 +43,8 @@ // Check for both libfoo.dylib and libfoo.tbd (in that order). llvm::Optional resolveDylibPath(llvm::StringRef path); -llvm::Optional makeDylibFromTAPI(llvm::MemoryBufferRef mbref, - DylibFile *umbrella = nullptr); +llvm::Optional loadDylib(llvm::MemoryBufferRef mbref, + DylibFile *umbrella = nullptr); uint32_t getModTime(llvm::StringRef path); diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -309,10 +309,8 @@ break; case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamically_linked_shared_lib_stub: - newFile = make(mbref); - break; case file_magic::tapi_file: { - if (Optional dylibFile = makeDylibFromTAPI(mbref)) + if (Optional dylibFile = loadDylib(mbref)) newFile = *dylibFile; break; } diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -14,6 +14,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -166,7 +167,7 @@ return {}; } -Optional macho::makeDylibFromTAPI(MemoryBufferRef mbref, +static Optional makeDylibFromTapi(MemoryBufferRef mbref, DylibFile *umbrella) { Expected> result = TextAPIReader::get(mbref); if (!result) { @@ -177,6 +178,24 @@ return make(**result, umbrella); } +static StringSet<> loadedDylibs; + +Optional macho::loadDylib(MemoryBufferRef mbref, + DylibFile *umbrella) { + StringRef path = mbref.getBufferIdentifier(); + if (loadedDylibs.contains(path)) + return {}; + loadedDylibs.insert(path); + + file_magic magic = identify_magic(mbref.getBuffer()); + if (magic == file_magic::tapi_file) + return makeDylibFromTapi(mbref, umbrella); + + assert(magic == file_magic::macho_dynamically_linked_shared_lib || + magic == file_magic::macho_dynamically_linked_shared_lib_stub); + return make(mbref, umbrella); +} + uint32_t macho::getModTime(StringRef path) { fs::file_status stat; if (!fs::status(path, stat)) diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -134,7 +134,6 @@ uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel bool reexport = false; bool forceWeakImport = false; - std::vector reexported; }; // .a file diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -457,12 +457,7 @@ error("could not read dylib file at " + path); return {}; } - - file_magic magic = identify_magic(mbref->getBuffer()); - if (magic == file_magic::tapi_file) - return makeDylibFromTAPI(*mbref, umbrella); - assert(magic == file_magic::macho_dynamically_linked_shared_lib); - return make(*mbref, umbrella); + return loadDylib(*mbref, umbrella); } // TBD files are parsed into a series of TAPI documents (InterfaceFiles), with @@ -518,11 +513,10 @@ // -sub_umbrella first to write a test case. } -static Optional loadReexport(StringRef path, DylibFile *umbrella) { +void loadReexport(StringRef path, DylibFile *umbrella) { Optional reexport = loadReexportHelper(path, umbrella); if (reexport && implicitlyLinked(path)) inputFiles.push_back(*reexport); - return reexport; } DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella) @@ -572,8 +566,7 @@ auto *c = reinterpret_cast(cmd); StringRef reexportPath = reinterpret_cast(c) + read32le(&c->dylib.name); - if (Optional reexport = loadReexport(reexportPath, umbrella)) - reexported.push_back(*reexport); + loadReexport(reexportPath, umbrella); } } @@ -621,9 +614,7 @@ } for (InterfaceFileRef intfRef : interface.reexportedLibraries()) - if (Optional reexport = - loadReexport(intfRef.getInstallName(), umbrella)) - reexported.push_back(*reexport); + loadReexport(intfRef.getInstallName(), umbrella); if (isTopLevelTapi) currentTopLevelTapi = nullptr; diff --git a/lld/test/MachO/dylink.s b/lld/test/MachO/dylink.s --- a/lld/test/MachO/dylink.s +++ b/lld/test/MachO/dylink.s @@ -38,6 +38,20 @@ # CHECK-DAG: __DATA __data 0x{{0*}}[[#%x, DATA_ADDR + 8]] pointer 8 libhello _hello_its_me # CHECK-DAG: __DATA __data 0x{{0*}}[[#%x, DATA_ADDR + 16]] pointer -15 libgoodbye _goodbye_world +# RUN: llvm-objdump --macho --all-headers %t/dylink | FileCheck %s \ +# RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB +## Check that we don't create duplicate LC_LOAD_DYLIBs. +# RUN: %lld -o %t/dylink -L%t -lhello -lhello -lgoodbye -lgoodbye %t/dylink.o +# RUN: llvm-objdump --macho --all-headers %t/dylink | FileCheck %s \ +# RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB + +# LOAD: cmd LC_LOAD_DYLIB +# LOAD-NEXT: cmdsize +# LOAD-NEXT: name @executable_path/libhello.dylib +# LOAD: cmd LC_LOAD_DYLIB +# LOAD-NEXT: cmdsize +# LOAD-NEXT: name @executable_path/libgoodbye.dylib + .section __TEXT,__text .globl _main diff --git a/lld/test/MachO/implicit-dylibs.s b/lld/test/MachO/implicit-dylibs.s --- a/lld/test/MachO/implicit-dylibs.s +++ b/lld/test/MachO/implicit-dylibs.s @@ -31,6 +31,11 @@ # RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s \ # RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB +## Check that we don't create duplicate LC_LOAD_DYLIBs. +# RUN: %lld -syslibroot %t -o %t/test -lSystem -L%t -lreexporter -ltoplevel %t/test.o +# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s \ +# RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB + # LOAD: cmd LC_LOAD_DYLIB # LOAD-NEXT: cmdsize # LOAD-NEXT: name /usr/lib/libSystem.B.dylib