Skip to content

Commit

Permalink
[lld-macho] Add support for exporting no symbols
Browse files Browse the repository at this point in the history
As an optimization for ld64 sometimes it can be useful to not export any
symbols for top level binaries that don't need any exports, to do this
you can pass `-exported_symbols_list /dev/null`, or new with Xcode 14
(ld64 816) there is a `-no_exported_symbols` flag for the same behavior.
This reproduces this behavior where previously an empty exported symbols
list file would have been ignored.

Differential Revision: https://reviews.llvm.org/D127562
  • Loading branch information
keith committed Jun 15, 2022
1 parent 3cd5696 commit 272bf0f
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
1 change: 1 addition & 0 deletions lld/MachO/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ struct Configuration {
SectionRenameMap sectionRenameMap;
SegmentRenameMap segmentRenameMap;

bool hasExplicitExports = false;
SymbolPatterns exportedSymbols;
SymbolPatterns unexportedSymbols;
SymbolPatterns whyLive;
Expand Down
15 changes: 9 additions & 6 deletions lld/MachO/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,15 +1403,18 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->segmentProtections.push_back({segName, maxProt, initProt});
}

config->hasExplicitExports =
args.hasArg(OPT_no_exported_symbols) ||
args.hasArgNoClaim(OPT_exported_symbol, OPT_exported_symbols_list);
handleSymbolPatterns(args, config->exportedSymbols, OPT_exported_symbol,
OPT_exported_symbols_list);
handleSymbolPatterns(args, config->unexportedSymbols, OPT_unexported_symbol,
OPT_unexported_symbols_list);
if (!config->exportedSymbols.empty() && !config->unexportedSymbols.empty()) {
error("cannot use both -exported_symbol* and -unexported_symbol* options\n"
">>> ignoring unexports");
config->unexportedSymbols.clear();
}
if (config->hasExplicitExports && !config->unexportedSymbols.empty())
error("cannot use both -exported_symbol* and -unexported_symbol* options");

if (args.hasArg(OPT_no_exported_symbols) && !config->exportedSymbols.empty())
error("cannot use both -exported_symbol* and -no_exported_symbols options");

// Imitating LD64's:
// -non_global_symbols_no_strip_list and -non_global_symbols_strip_list can't
Expand Down Expand Up @@ -1555,7 +1558,7 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
createSyntheticSections();
createSyntheticSymbols();

if (!config->exportedSymbols.empty()) {
if (config->hasExplicitExports) {
parallelForEach(symtab->getSymbols(), [](Symbol *sym) {
if (auto *defined = dyn_cast<Defined>(sym)) {
StringRef symbolName = defined->getName();
Expand Down
3 changes: 3 additions & 0 deletions lld/MachO/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,9 @@ def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
MetaVarName<"<file>">,
HelpText<"Symbols specified in <file> remain global, while others become private externs">,
Group<grp_resolve>;
def no_exported_symbols : Flag<["-"], "no_exported_symbols">,
HelpText<"Don't export any symbols from the binary, useful for main executables that don't have plugins">,
Group<grp_resolve>;
def unexported_symbol : Separate<["-"], "unexported_symbol">,
MetaVarName<"<symbol>">,
HelpText<"Global <symbol> becomes private extern">,
Expand Down
30 changes: 29 additions & 1 deletion lld/test/MachO/export-options.s
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,26 @@
# RUN: not %lld -dylib %t/default.o -o /dev/null \
# RUN: -exported_symbol a -unexported_symbol b 2>&1 | \
# RUN: FileCheck --check-prefix=CONFLICT %s
#
# RUN: not %lld -dylib %t/default.o -o /dev/null \
# RUN: -exported_symbols_list /dev/null -unexported_symbol b 2>&1 | \
# RUN: FileCheck --check-prefix=CONFLICT %s
#
# RUN: not %lld -dylib %t/default.o -o /dev/null \
# RUN: -no_exported_symbols -unexported_symbol b 2>&1 | \
# RUN: FileCheck --check-prefix=CONFLICT %s
#
# RUN: not %lld -dylib %t/default.o -o /dev/null \
# RUN: -no_exported_symbols -exported_symbol b 2>&1 | \
# RUN: FileCheck --check-prefix=CONFLICT-NO-EXPORTS %s
#
# RUN: not %lld -dylib %t/default.o -o /dev/null \
# RUN: -no_exported_symbols -exported_symbols_list %t/literals.txt 2>&1 | \
# RUN: FileCheck --check-prefix=CONFLICT-NO-EXPORTS %s

# CONFLICT: error: cannot use both -exported_symbol* and -unexported_symbol* options
# CONFLICT-NEXT: >>> ignoring unexports

# CONFLICT-NO-EXPORTS: error: cannot use both -exported_symbol* and -no_exported_symbols options

## Check that an exported literal name with no symbol definition yields an error
## but that an exported glob-pattern with no matching symbol definition is OK
Expand Down Expand Up @@ -162,6 +179,17 @@
# AUTOHIDE-PRIVATE: error: cannot export hidden symbol _foo
# AUTOHIDE-PRIVATE-DEAD-STRIP: (__TEXT,__text) non-external (was a private external) _foo

## Test not exporting any symbols
# RUN: %lld -dylib %t/symdefs.o -o %t/noexports -exported_symbols_list /dev/null
# RUN: llvm-objdump --macho --exports-trie %t/noexports | FileCheck --check-prefix=NOEXPORTS %s
# RUN: %lld -dylib %t/symdefs.o -o %t/noexports -no_exported_symbols
# RUN: llvm-objdump --macho --exports-trie %t/noexports | FileCheck --check-prefix=NOEXPORTS %s

# NOEXPORTS-NOT: globby_also
# NOEXPORTS-NOT: globby_only
# NOEXPORTS-NOT: literal_also
# NOEXPORTS-NOT: literal_only

#--- default.s

.globl _keep_globl, _hide_globl
Expand Down

0 comments on commit 272bf0f

Please sign in to comment.