[lld] Do not implicitly link non "public" libraries (#97639)

The LC_SUB_CLIENT Mach-O command and the `allowable-clients` TBD entry
specify that the given framework (or library?) can only be linked
directly from the specified names, even if it is sitting in `/usr/lib`
or `/System/Library/Frameworks`.

Add a check for those conditions before checking if a library should be
implicitly linked, and link against their umbrella if they have
allowable clients. The code needs to be in both the binary libraries and
the interface libraries.

Add a test that reproduces the scenario in which a framework reexports a
private framework that sits in `/System/Library/Frameworks`, and check
for the symbols of the reexported framework to be associated with the
public framework, and not the private one.
This commit is contained in:
Daniel Rodríguez Troitiño
2024-07-08 09:26:16 -07:00
committed by GitHub
parent fe8933ba21
commit 840e507544
2 changed files with 57 additions and 2 deletions

View File

@@ -1725,7 +1725,10 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
}
// Initialize symbols.
exportingFile = isImplicitlyLinked(installName) ? this : this->umbrella;
bool canBeImplicitlyLinked = findCommand(hdr, LC_SUB_CLIENT) == nullptr;
exportingFile = (canBeImplicitlyLinked && isImplicitlyLinked(installName))
? this
: this->umbrella;
const auto *dyldInfo = findCommand<dyld_info_command>(hdr, LC_DYLD_INFO_ONLY);
const auto *exportsTrie =
@@ -1884,7 +1887,10 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
checkAppExtensionSafety(interface.isApplicationExtensionSafe());
exportingFile = isImplicitlyLinked(installName) ? this : umbrella;
bool canBeImplicitlyLinked = interface.allowableClients().size() == 0;
exportingFile = (canBeImplicitlyLinked && isImplicitlyLinked(installName))
? this
: umbrella;
auto addSymbol = [&](const llvm::MachO::Symbol &symbol,
const Twine &name) -> void {
StringRef savedName = saver().save(name);

View File

@@ -0,0 +1,49 @@
# REQUIRES: arm
# RUN: rm -rf %t; split-file %s %t
# RUN: ln -s Versions/A/FrameworkPublic.tbd %t/System/Library/Frameworks/FrameworkPublic.framework/
# RUN: ln -s Versions/A/FrameworkPrivate.tbd %t/System/Library/Frameworks/FrameworkPrivate.framework/
# RUN: llvm-mc -filetype obj -triple arm64-apple-macos11.0 %t/test.s -o %t/test.o
# RUN: %lld -arch arm64 -platform_version macos 11.0 11.0 -o %t/test -syslibroot %t -framework FrameworkPublic %t/test.o
# RUN: llvm-objdump --bind --no-show-raw-insn -d %t/test | FileCheck %s
# CHECK: Bind table:
# CHECK-DAG: __DATA __data {{.*}} pointer 0 FrameworkPublic _funcPublic
# CHECK-DAG: __DATA __data {{.*}} pointer 0 FrameworkPublic _funcPrivate
#--- System/Library/Frameworks/FrameworkPublic.framework/Versions/A/FrameworkPublic.tbd
--- !tapi-tbd
tbd-version: 4
targets: [ arm64-macos ]
install-name: '/System/Library/Frameworks/FrameworkPublic.framework/Versions/A/FrameworkPublic'
current-version: 1.0.0
reexported-libraries:
- targets: [ arm64-macos ]
libraries: [ '/System/Library/Frameworks/FrameworkPrivate.framework/Versions/A/FrameworkPrivate' ]
exports:
- targets: [ arm64-macos ]
symbols: [ '_funcPublic' ]
...
#--- System/Library/Frameworks/FrameworkPrivate.framework/Versions/A/FrameworkPrivate.tbd
--- !tapi-tbd
tbd-version: 4
targets: [ arm64-macos ]
install-name: '/System/Library/Frameworks/FrameworkPrivate.framework/Versions/A/FrameworkPrivate'
current-version: 1.0.0
allowable-clients:
- targets: [ arm64-macos ]
clients: [ FrameworkPublic ]
exports:
- targets: [ arm64-macos ]
symbols: [ '_funcPrivate' ]
...
#--- test.s
.text
.globl _main
_main:
ret
.data
.quad _funcPublic
.quad _funcPrivate