forked from OSchip/llvm-project
[lld/mac] Implement removal of unused dylibs
This omits load commands for unreferenced dylibs if: - the dylib was loaded implicitly, - it is marked MH_DEAD_STRIPPABLE_DYLIB - or -dead_strip_dylibs is passed This matches ld64. Currently, the "is dylib referenced" state is computed before dead code stripping and is not updated after dead code stripping. This too matches ld64. We should do better here. With this, clang-format linked with lld (like with ld64) no longer has libobjc.A.dylib in `otool -L` output. (It was implicitly loaded as a reexport of CoreFoundation.framework, but it's not needed.) Differential Revision: https://reviews.llvm.org/D103430
This commit is contained in:
parent
936ca1e21a
commit
2c1903412b
|
@ -109,6 +109,7 @@ struct Configuration {
|
|||
llvm::StringRef outputFile;
|
||||
llvm::StringRef ltoObjPath;
|
||||
llvm::StringRef thinLTOJobs;
|
||||
bool deadStripDylibs = false;
|
||||
bool demangle = false;
|
||||
PlatformInfo platformInfo;
|
||||
NamespaceKind namespaceKind = NamespaceKind::twolevel;
|
||||
|
|
|
@ -293,8 +293,10 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
|
|||
case file_magic::macho_dynamically_linked_shared_lib:
|
||||
case file_magic::macho_dynamically_linked_shared_lib_stub:
|
||||
case file_magic::tapi_file:
|
||||
if (Optional<DylibFile *> dylibFile = loadDylib(mbref))
|
||||
if (Optional<DylibFile *> dylibFile = loadDylib(mbref)) {
|
||||
(*dylibFile)->explicitlyLinked = true;
|
||||
newFile = *dylibFile;
|
||||
}
|
||||
break;
|
||||
case file_magic::bitcode:
|
||||
newFile = make<BitcodeFile>(mbref);
|
||||
|
@ -322,21 +324,25 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
|
|||
return newFile;
|
||||
}
|
||||
|
||||
static void addLibrary(StringRef name, bool isWeak) {
|
||||
static void addLibrary(StringRef name, bool isWeak, bool isExplicit = true) {
|
||||
if (Optional<StringRef> path = findLibrary(name)) {
|
||||
auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
|
||||
if (isWeak && dylibFile)
|
||||
dylibFile->forceWeakImport = true;
|
||||
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false))) {
|
||||
dylibFile->explicitlyLinked = isExplicit;
|
||||
if (isWeak)
|
||||
dylibFile->forceWeakImport = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
error("library not found for -l" + name);
|
||||
}
|
||||
|
||||
static void addFramework(StringRef name, bool isWeak) {
|
||||
static void addFramework(StringRef name, bool isWeak, bool isExplicit = true) {
|
||||
if (Optional<std::string> path = findFramework(name)) {
|
||||
auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
|
||||
if (isWeak && dylibFile)
|
||||
dylibFile->forceWeakImport = true;
|
||||
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false))) {
|
||||
dylibFile->explicitlyLinked = isExplicit;
|
||||
if (isWeak)
|
||||
dylibFile->forceWeakImport = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
error("framework not found for -framework " + name);
|
||||
|
@ -365,10 +371,10 @@ void macho::parseLCLinkerOption(InputFile *f, unsigned argc, StringRef data) {
|
|||
for (const Arg *arg : args) {
|
||||
switch (arg->getOption().getID()) {
|
||||
case OPT_l:
|
||||
addLibrary(arg->getValue(), false);
|
||||
addLibrary(arg->getValue(), /*isWeak=*/false, /*isExplicit=*/false);
|
||||
break;
|
||||
case OPT_framework:
|
||||
addFramework(arg->getValue(), false);
|
||||
addFramework(arg->getValue(), /*isWeak=*/false, /*isExplicit=*/false);
|
||||
break;
|
||||
default:
|
||||
error(arg->getSpelling() + " is not allowed in LC_LINKER_OPTION");
|
||||
|
@ -981,6 +987,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
|
|||
config->runtimePaths = args::getStrings(args, OPT_rpath);
|
||||
config->allLoad = args.hasArg(OPT_all_load);
|
||||
config->forceLoadObjC = args.hasArg(OPT_ObjC);
|
||||
config->deadStripDylibs = args.hasArg(OPT_dead_strip_dylibs);
|
||||
config->demangle = args.hasArg(OPT_demangle);
|
||||
config->implicitDylibs = !args.hasArg(OPT_no_implicit_dylibs);
|
||||
config->emitFunctionStarts = !args.hasArg(OPT_no_function_starts);
|
||||
|
|
|
@ -828,6 +828,8 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
|
|||
return;
|
||||
}
|
||||
|
||||
deadStrippable = hdr->flags & MH_DEAD_STRIPPABLE_DYLIB;
|
||||
|
||||
if (!checkCompatibility(this))
|
||||
return;
|
||||
|
||||
|
|
|
@ -157,6 +157,14 @@ public:
|
|||
RefState refState;
|
||||
bool reexport = false;
|
||||
bool forceWeakImport = false;
|
||||
bool deadStrippable = false;
|
||||
bool explicitlyLinked = false;
|
||||
|
||||
unsigned numReferencedSymbols = 0;
|
||||
|
||||
bool isReferenced() const {
|
||||
return numReferencedSymbols > 0;
|
||||
}
|
||||
|
||||
// An executable can be used as a bundle loader that will load the output
|
||||
// file being linked, and that contains symbols referenced, but not
|
||||
|
|
|
@ -702,7 +702,6 @@ def objc_gc_only : Flag<["-"], "objc_gc_only">,
|
|||
Group<grp_rare>;
|
||||
def dead_strip_dylibs : Flag<["-"], "dead_strip_dylibs">,
|
||||
HelpText<"Remove dylibs that are unreachable by the entry point or exported symbols">,
|
||||
Flags<[HelpHidden]>,
|
||||
Group<grp_rare>;
|
||||
def allow_sub_type_mismatches : Flag<["-"], "allow_sub_type_mismatches">,
|
||||
HelpText<"Permit mixing objects compiled for different ARM CPU subtypes">,
|
||||
|
|
|
@ -81,6 +81,7 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
|
|||
toString(file));
|
||||
} else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
|
||||
overridesWeakDef = !isWeakDef && dysym->isWeakDef();
|
||||
dysym->unreference();
|
||||
}
|
||||
// Defined symbols take priority over other types of symbols, so in case
|
||||
// of a name conflict, we fall through to the replaceSymbol() call below.
|
||||
|
@ -106,7 +107,7 @@ Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file,
|
|||
else if (auto *lazy = dyn_cast<LazySymbol>(s))
|
||||
lazy->fetchArchiveMember();
|
||||
else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
|
||||
dynsym->refState = std::max(dynsym->refState, refState);
|
||||
dynsym->reference(refState);
|
||||
else if (auto *undefined = dyn_cast<Undefined>(s))
|
||||
undefined->refState = std::max(undefined->refState, refState);
|
||||
return s;
|
||||
|
@ -147,7 +148,7 @@ Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
|
|||
} else if (auto *undefined = dyn_cast<Undefined>(s)) {
|
||||
refState = undefined->refState;
|
||||
} else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
|
||||
refState = dysym->refState;
|
||||
refState = dysym->getRefState();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,8 +156,11 @@ Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
|
|||
if (wasInserted || isa<Undefined>(s) ||
|
||||
(isa<DylibSymbol>(s) &&
|
||||
((!isWeakDef && s->isWeakDef()) ||
|
||||
(!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup()))))
|
||||
(!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) {
|
||||
if (auto *dynsym = dyn_cast<DylibSymbol>(s))
|
||||
dynsym->unreference();
|
||||
replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -221,7 +221,10 @@ public:
|
|||
DylibSymbol(DylibFile *file, StringRefZ name, bool isWeakDef,
|
||||
RefState refState, bool isTlv)
|
||||
: Symbol(DylibKind, name, file), refState(refState), weakDef(isWeakDef),
|
||||
tlv(isTlv) {}
|
||||
tlv(isTlv) {
|
||||
if (file && refState > RefState::Unreferenced)
|
||||
file->numReferencedSymbols++;
|
||||
}
|
||||
|
||||
uint64_t getVA() const override;
|
||||
bool isWeakDef() const override { return weakDef; }
|
||||
|
@ -241,9 +244,25 @@ public:
|
|||
uint32_t stubsHelperIndex = UINT32_MAX;
|
||||
uint32_t lazyBindOffset = UINT32_MAX;
|
||||
|
||||
RefState refState : 2;
|
||||
RefState getRefState() const { return refState; }
|
||||
|
||||
void reference(RefState newState) {
|
||||
assert(newState > RefState::Unreferenced);
|
||||
if (refState == RefState::Unreferenced && file)
|
||||
getFile()->numReferencedSymbols++;
|
||||
refState = std::max(refState, newState);
|
||||
}
|
||||
|
||||
void unreference() {
|
||||
// dynamic_lookup symbols have no file.
|
||||
if (refState > RefState::Unreferenced && file) {
|
||||
assert(getFile()->numReferencedSymbols > 0);
|
||||
getFile()->numReferencedSymbols--;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RefState refState : 2;
|
||||
const bool weakDef : 1;
|
||||
const bool tlv : 1;
|
||||
};
|
||||
|
|
|
@ -312,9 +312,10 @@ static void encodeBinding(const Symbol *sym, const OutputSection *osec,
|
|||
|
||||
// Non-weak bindings need to have their dylib ordinal encoded as well.
|
||||
static int16_t ordinalForDylibSymbol(const DylibSymbol &dysym) {
|
||||
return config->namespaceKind == NamespaceKind::flat || dysym.isDynamicLookup()
|
||||
? static_cast<int16_t>(BIND_SPECIAL_DYLIB_FLAT_LOOKUP)
|
||||
: dysym.getFile()->ordinal;
|
||||
if (config->namespaceKind == NamespaceKind::flat || dysym.isDynamicLookup())
|
||||
return static_cast<int16_t>(BIND_SPECIAL_DYLIB_FLAT_LOOKUP);
|
||||
assert(dysym.getFile()->isReferenced());
|
||||
return dysym.getFile()->ordinal;
|
||||
}
|
||||
|
||||
static void encodeDylibOrdinal(int16_t ordinal, raw_svector_ostream &os) {
|
||||
|
@ -464,7 +465,7 @@ void StubHelperSection::setup() {
|
|||
"Needed to perform lazy binding.");
|
||||
return;
|
||||
}
|
||||
stubBinder->refState = RefState::Strong;
|
||||
stubBinder->reference(RefState::Strong);
|
||||
in.got->addEntry(stubBinder);
|
||||
|
||||
inputSections.push_back(in.imageLoaderCache);
|
||||
|
|
|
@ -615,7 +615,7 @@ void Writer::scanSymbols() {
|
|||
if (dysym->isDynamicLookup())
|
||||
continue;
|
||||
dysym->getFile()->refState =
|
||||
std::max(dysym->getFile()->refState, dysym->refState);
|
||||
std::max(dysym->getFile()->refState, dysym->getRefState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -688,6 +688,19 @@ template <class LP> void Writer::createLoadCommands() {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Don't emit load commands for a dylib that is not referenced if:
|
||||
// - it was added implicitly (via a reexport, an LC_LOAD_DYLINKER --
|
||||
// if it's on the linker command line, it's explicit)
|
||||
// - or it's marked MH_DEAD_STRIPPABLE_DYLIB
|
||||
// - or the flag -dead_strip_dylibs is used
|
||||
// FIXME: `isReferenced()` is currently computed before dead code
|
||||
// stripping, so references from dead code keep a dylib alive. This
|
||||
// matches ld64, but it's something we should do better.
|
||||
if (!dylibFile->isReferenced() &&
|
||||
(!dylibFile->explicitlyLinked || dylibFile->deadStrippable ||
|
||||
config->deadStripDylibs))
|
||||
continue;
|
||||
|
||||
dylibFile->ordinal = dylibOrdinal++;
|
||||
LoadCommandType lcType =
|
||||
dylibFile->forceWeakImport || dylibFile->refState == RefState::Weak
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
# REQUIRES: x86
|
||||
|
||||
# RUN: rm -rf %t; split-file %s %t
|
||||
|
||||
# RUN: llvm-mc %t/bar.s -triple=x86_64-apple-macos -filetype=obj -o %t/bar.o
|
||||
# RUN: %lld -dylib %t/bar.o -o %t/bar.dylib
|
||||
# RUN: %lld -dylib -mark_dead_strippable_dylib %t/bar.o -o %t/bar-strip.dylib
|
||||
|
||||
# RUN: llvm-mc %t/foo.s -triple=x86_64-apple-macos -filetype=obj -o %t/foo.o
|
||||
# RUN: %lld -dylib %t/foo.o -o %t/foo_with_bar.dylib %t/bar.dylib -sub_library bar
|
||||
# RUN: %lld -dylib %t/foo.o -o %t/foo.dylib
|
||||
|
||||
# RUN: llvm-mc %t/weak-foo.s -triple=x86_64-apple-macos -filetype=obj -o %t/weak-foo.o
|
||||
# RUN: %lld -dylib %t/weak-foo.o -o %t/weak-foo.dylib
|
||||
|
||||
# RUN: llvm-mc %t/main.s -triple=x86_64-apple-macos -filetype=obj -o %t/main.o
|
||||
|
||||
## foo_with_bar.dylib's reexport should be dropped since it's linked implicitly.
|
||||
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo_with_bar.dylib
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBAR %s
|
||||
# NOBAR-NOT: bar.dylib
|
||||
# NOBAR: /usr/lib/libSystem.dylib
|
||||
# NOBAR-NOT: bar.dylib
|
||||
# NOBAR: foo_with_bar.dylib
|
||||
# NOBAR-NOT: bar.dylib
|
||||
|
||||
## If bar.dylib is linked explicitly, it should not be dropped.
|
||||
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo_with_bar.dylib %t/bar.dylib
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=BAR %s
|
||||
# BAR: /usr/lib/libSystem.dylib
|
||||
# BAR: foo_with_bar.dylib
|
||||
# BAR: bar.dylib
|
||||
|
||||
## ...except if -dead-strip_dylibs is passed...
|
||||
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo_with_bar.dylib %t/bar.dylib \
|
||||
# RUN: -dead_strip_dylibs
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBAR %s
|
||||
|
||||
## ...or bar is explicitly marked dead-strippable
|
||||
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo.dylib %t/bar-strip.dylib
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBARSTRIP %s
|
||||
# NOBARSTRIP-NOT: bar-strip.dylib
|
||||
# NOBARSTRIP: /usr/lib/libSystem.dylib
|
||||
# NOBARSTRIP-NOT: bar-strip.dylib
|
||||
# NOBARSTRIP: foo.dylib
|
||||
# NOBARSTRIP-NOT: bar-strip.dylib
|
||||
|
||||
## LC_LINKER_OPTION does not count as an explicit reference.
|
||||
# RUN: llvm-mc %t/linkopt_bar.s -triple=x86_64-apple-macos -filetype=obj -o %t/linkopt_bar.o
|
||||
# RUN: %lld -dylib %t/bar.o -o %t/libbar.dylib
|
||||
# RUN: %lld -lSystem %t/main.o %t/linkopt_bar.o -o %t/main -L %t %t/foo_with_bar.dylib
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBAR %s
|
||||
|
||||
## Test that a DylibSymbol being replaced by a DefinedSymbol marks the
|
||||
## dylib as unreferenced.
|
||||
## (Note: Since there's no dynamic linking in this example, libSystem is
|
||||
## stripped too. Since libSystem.dylib is needed to run an executable for
|
||||
## LC_MAIN, the output would crash when run. This matches ld64's behavior (!)
|
||||
## In practice, every executable uses dynamic linking, which uses
|
||||
## dyld_stub_binder, which keeps libSystem alive.)
|
||||
## Test all permutations of (Undefined, Defined, DylibSymbol).
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/main.o %t/foo.o %t/foo.dylib -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/main.o %t/foo.dylib %t/foo.dylib %t/foo.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/foo.o %t/main.o %t/foo.dylib -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/foo.dylib %t/foo.dylib %t/main.o %t/foo.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/foo.o %t/foo.dylib %t/main.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/foo.dylib %t/foo.dylib %t/foo.o %t/main.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOFOO %s
|
||||
# NOFOO-NOT: foo.dylib
|
||||
|
||||
## When linking a weak and a strong symbol from two dylibs, we should keep the
|
||||
## strong one.
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/main.o %t/foo.dylib %t/weak-foo.dylib -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOWEAK %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/main.o %t/weak-foo.dylib %t/foo.dylib -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOWEAK %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/foo.dylib %t/weak-foo.dylib %t/main.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOWEAK %s
|
||||
# RUN: %lld -lSystem -dead_strip_dylibs %t/weak-foo.dylib %t/foo.dylib %t/main.o -o %t/main
|
||||
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOWEAK %s
|
||||
# NOWEAK-NOT: weak-foo.dylib
|
||||
# NOWEAK: /foo.dylib
|
||||
# NOWEAK-NOT: weak-foo.dylib
|
||||
|
||||
#--- main.s
|
||||
.globl _foo, _main
|
||||
_main:
|
||||
callq _foo
|
||||
retq
|
||||
|
||||
#--- foo.s
|
||||
.globl _foo
|
||||
_foo:
|
||||
retq
|
||||
|
||||
#--- bar.s
|
||||
.globl _bar
|
||||
_bar:
|
||||
retq
|
||||
|
||||
#--- linkopt_bar.s
|
||||
.linker_option "-lbar"
|
||||
|
||||
#--- weak-foo.s
|
||||
.globl _foo
|
||||
.weak_definition _foo
|
||||
_foo:
|
||||
retq
|
|
@ -58,11 +58,11 @@
|
|||
# CHECK-DAG: __DATA __data {{.*}} pointer 0 libreexporter _framework_baz
|
||||
# CHECK-DAG: __DATA __data {{.*}} pointer 0 libc++abi ___gxx_personality_v0
|
||||
|
||||
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s \
|
||||
# RUN: llvm-otool -l %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: llvm-otool -l %t/test | FileCheck %s \
|
||||
# RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB
|
||||
|
||||
# LOAD: cmd LC_LOAD_DYLIB
|
||||
|
@ -76,15 +76,9 @@
|
|||
# LOAD-NEXT: name /usr/lib/libc++abi.dylib
|
||||
# LOAD: cmd LC_LOAD_DYLIB
|
||||
# LOAD-NEXT: cmdsize
|
||||
# LOAD-NEXT: name /usr/lib/libc++.dylib
|
||||
# LOAD: cmd LC_LOAD_DYLIB
|
||||
# LOAD-NEXT: cmdsize
|
||||
# LOAD-NEXT: name /usr/lib/libtoplevel.dylib
|
||||
# LOAD: cmd LC_LOAD_DYLIB
|
||||
# LOAD-NEXT: cmdsize
|
||||
# LOAD-NEXT: name /usr/lib/libunused.dylib
|
||||
# LOAD: cmd LC_LOAD_DYLIB
|
||||
# LOAD-NEXT: cmdsize
|
||||
# LOAD-NEXT: name [[DIR]]/libreexporter.dylib
|
||||
|
||||
# RUN: %lld -no_implicit_dylibs -syslibroot %t -o %t/no-implicit -lSystem -L%t -lreexporter %t/test.o
|
||||
|
|
|
@ -2,30 +2,38 @@
|
|||
; RUN: rm -rf %t; split-file %s %t
|
||||
;
|
||||
; RUN: llvm-as %t/framework.ll -o %t/framework.o
|
||||
; RUN: %lld %t/framework.o -o %t/frame
|
||||
; RUN: llvm-objdump --macho --all-headers %t/frame | FileCheck --check-prefix=FRAME %s \
|
||||
; RUN: %lld -lSystem %t/framework.o -o %t/frame
|
||||
; RUN: llvm-otool -l %t/frame | FileCheck --check-prefix=FRAME %s \
|
||||
; RUN: --implicit-check-not LC_LOAD_DYLIB
|
||||
; FRAME: cmd LC_LOAD_DYLIB
|
||||
; FRAME-NEXT: cmdsize
|
||||
; FRAME-NEXT: name /usr/lib/libSystem.dylib
|
||||
; FRAME: cmd LC_LOAD_DYLIB
|
||||
; FRAME-NEXT: cmdsize
|
||||
; FRAME-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
|
||||
;
|
||||
|
||||
; RUN: llvm-as %t/l.ll -o %t/l.o
|
||||
; RUN: %lld %t/l.o -o %t/l
|
||||
; RUN: llvm-objdump --macho --all-headers %t/l | FileCheck --check-prefix=LIB %s \
|
||||
; RUN: --implicit-check-not LC_LOAD_DYLIB
|
||||
;
|
||||
;; Check that we don't create duplicate LC_LOAD_DYLIBs.
|
||||
; RUN: %lld -lSystem %t/l.o -o %t/l
|
||||
; RUN: llvm-objdump --macho --all-headers %t/l | FileCheck --check-prefix=LIB %s \
|
||||
;; The dynamic call to _CFBigNumGetInt128 uses dyld_stub_binder,
|
||||
;; which needs -lSystem from LC_LINKER_OPTION to get resolved.
|
||||
; RUN: %lld %t/l.o -o %t/l -framework CoreFoundation
|
||||
; RUN: llvm-otool -l %t/l | FileCheck --check-prefix=LIB %s \
|
||||
; RUN: --implicit-check-not LC_LOAD_DYLIB
|
||||
; LIB: cmd LC_LOAD_DYLIB
|
||||
; LIB-NEXT: cmdsize
|
||||
; LIB-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
|
||||
; LIB: cmd LC_LOAD_DYLIB
|
||||
; LIB-NEXT: cmdsize
|
||||
; LIB-NEXT: name /usr/lib/libSystem.dylib
|
||||
|
||||
;; Check that we don't create duplicate LC_LOAD_DYLIBs.
|
||||
; RUN: %lld -lSystem %t/l.o -o %t/l -framework CoreFoundation
|
||||
; RUN: llvm-otool -l %t/l | FileCheck --check-prefix=FRAME %s \
|
||||
; RUN: --implicit-check-not LC_LOAD_DYLIB
|
||||
;
|
||||
; RUN: llvm-as %t/invalid.ll -o %t/invalid.o
|
||||
; RUN: not %lld %t/invalid.o -o /dev/null 2>&1 | FileCheck --check-prefix=INVALID %s
|
||||
; INVALID: error: -why_load is not allowed in LC_LINKER_OPTION
|
||||
;
|
||||
|
||||
;--- framework.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"
|
||||
|
@ -33,7 +41,10 @@ target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
|
|||
!0 = !{!"-framework", !"CoreFoundation"}
|
||||
!llvm.linker.options = !{!0}
|
||||
|
||||
declare void @_CFBigNumGetInt128(...)
|
||||
|
||||
define void @main() {
|
||||
call void bitcast (void (...)* @_CFBigNumGetInt128 to void ()*)()
|
||||
ret void
|
||||
}
|
||||
|
||||
|
@ -44,7 +55,10 @@ target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
|
|||
!0 = !{!"-lSystem"}
|
||||
!llvm.linker.options = !{!0, !0}
|
||||
|
||||
declare void @_CFBigNumGetInt128(...)
|
||||
|
||||
define void @main() {
|
||||
call void bitcast (void (...)* @_CFBigNumGetInt128 to void ()*)()
|
||||
ret void
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue