[lld] fae6bd7 - [lld-macho] Support -non_global_symbols_strip_list, -non_global_symbols_no_strip_list, -x
Vy Nguyen via llvm-commits
llvm-commits at lists.llvm.org
Wed May 25 05:27:30 PDT 2022
Author: Vy Nguyen
Date: 2022-05-25T19:22:04+07:00
New Revision: fae6bd7563ca54139d6f7f66683c12b88783501f
URL: https://github.com/llvm/llvm-project/commit/fae6bd7563ca54139d6f7f66683c12b88783501f
DIFF: https://github.com/llvm/llvm-project/commit/fae6bd7563ca54139d6f7f66683c12b88783501f.diff
LOG: [lld-macho] Support -non_global_symbols_strip_list, -non_global_symbols_no_strip_list, -x
PR/55600
Differential Revision: https://reviews.llvm.org/D126046
Added:
lld/test/MachO/local-symbol-output.s
Modified:
lld/MachO/Config.h
lld/MachO/Driver.cpp
lld/MachO/Options.td
lld/MachO/SyntheticSections.cpp
Removed:
################################################################################
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index 46b3dca0c03dd..de64dc47591d1 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -94,6 +94,13 @@ class SymbolPatterns {
bool match(llvm::StringRef symbolName) const;
};
+enum class SymtabPresence {
+ All,
+ None,
+ SelectivelyIncluded,
+ SelectivelyExcluded,
+};
+
struct Configuration {
Symbol *entry = nullptr;
bool hasReexports = false;
@@ -179,6 +186,9 @@ struct Configuration {
SymbolPatterns unexportedSymbols;
SymbolPatterns whyLive;
+ SymtabPresence localSymbolsPresence = SymtabPresence::All;
+ SymbolPatterns localSymbolPatterns;
+
bool zeroModTime = false;
llvm::StringRef osoPrefix;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index bfbfb26bb6b54..c04c4fb1899bb 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -938,26 +938,29 @@ bool SymbolPatterns::match(StringRef symbolName) const {
return matchLiteral(symbolName) || matchGlob(symbolName);
}
+static void handleSymbolPatternsListHelper(const Arg *arg,
+ SymbolPatterns &symbolPatterns) {
+ StringRef path = arg->getValue();
+ Optional<MemoryBufferRef> buffer = readFile(path);
+ if (!buffer) {
+ error("Could not read symbol file: " + path);
+ return;
+ }
+ MemoryBufferRef mbref = *buffer;
+ for (StringRef line : args::getLines(mbref)) {
+ line = line.take_until([](char c) { return c == '#'; }).trim();
+ if (!line.empty())
+ symbolPatterns.insert(line);
+ }
+}
static void handleSymbolPatterns(InputArgList &args,
SymbolPatterns &symbolPatterns,
unsigned singleOptionCode,
unsigned listFileOptionCode) {
for (const Arg *arg : args.filtered(singleOptionCode))
symbolPatterns.insert(arg->getValue());
- for (const Arg *arg : args.filtered(listFileOptionCode)) {
- StringRef path = arg->getValue();
- Optional<MemoryBufferRef> buffer = readFile(path);
- if (!buffer) {
- error("Could not read symbol file: " + path);
- continue;
- }
- MemoryBufferRef mbref = *buffer;
- for (StringRef line : args::getLines(mbref)) {
- line = line.take_until([](char c) { return c == '#'; }).trim();
- if (!line.empty())
- symbolPatterns.insert(line);
- }
- }
+ for (const Arg *arg : args.filtered(listFileOptionCode))
+ handleSymbolPatternsListHelper(arg, symbolPatterns);
}
static void createFiles(const InputArgList &args) {
@@ -1406,9 +1409,53 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
">>> ignoring unexports");
config->unexportedSymbols.clear();
}
+
+ // Imitating LD64's:
+ // -non_global_symbols_no_strip_list and -non_global_symbols_strip_list can't
+ // both be present.
+ // But -x can be used with either of these two, in which case, the last arg
+ // takes effect.
+ // (TODO: This is kind of confusing - considering disallowing using them
+ // together for a more straightforward behaviour)
+ {
+ bool includeLocal = false;
+ bool excludeLocal = false;
+ for (const Arg *arg :
+ args.filtered(OPT_x, OPT_non_global_symbols_no_strip_list,
+ OPT_non_global_symbols_strip_list)) {
+ switch (arg->getOption().getID()) {
+ case OPT_x:
+ config->localSymbolsPresence = SymtabPresence::None;
+
+ break;
+ case OPT_non_global_symbols_no_strip_list:
+ if (excludeLocal) {
+ error("cannot use both -non_global_symbols_no_strip_list and "
+ "-non_global_symbols_strip_list");
+ } else {
+ includeLocal = true;
+ config->localSymbolsPresence = SymtabPresence::SelectivelyIncluded;
+ handleSymbolPatternsListHelper(arg, config->localSymbolPatterns);
+ }
+ break;
+ case OPT_non_global_symbols_strip_list:
+ if (includeLocal) {
+ error("cannot use both -non_global_symbols_no_strip_list and "
+ "-non_global_symbols_strip_list");
+ } else {
+ excludeLocal = true;
+ config->localSymbolsPresence = SymtabPresence::SelectivelyExcluded;
+ handleSymbolPatternsListHelper(arg, config->localSymbolPatterns);
+ }
+ break;
+ default:
+ llvm_unreachable("unexpected option");
+ }
+ }
+ }
// Explicitly-exported literal symbols must be defined, but might
- // languish in an archive if unreferenced elsewhere. Light a fire
- // under those lazy symbols!
+ // languish in an archive if unreferenced elsewhere or if they are in the
+ // non-global strip list. Light a fire under those lazy symbols!
for (const CachedHashStringRef &cachedName : config->exportedSymbols.literals)
symtab->addUndefined(cachedName.val(), /*file=*/nullptr,
/*isWeakRef=*/false);
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 5678ae567f935..21d9dc00b5bb9 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -581,17 +581,14 @@ def S : Flag<["-"], "S">,
Group<grp_symtab>;
def x : Flag<["-"], "x">,
HelpText<"Exclude non-global symbols from the output symbol table">,
- Flags<[HelpHidden]>,
Group<grp_symtab>;
def non_global_symbols_strip_list : Separate<["-"], "non_global_symbols_strip_list">,
MetaVarName<"<path>">,
HelpText<"Specify in <path> the non-global symbols that should be removed from the output symbol table">,
- Flags<[HelpHidden]>,
Group<grp_symtab>;
def non_global_symbols_no_strip_list : Separate<["-"], "non_global_symbols_no_strip_list">,
MetaVarName<"<path>">,
HelpText<"Specify in <path> the non-global symbols that should remain in the output symbol table">,
- Flags<[HelpHidden]>,
Group<grp_symtab>;
def oso_prefix : Separate<["-"], "oso_prefix">,
MetaVarName<"<path>">,
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 61597ccf9ebf5..3a5e9daad7291 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -963,16 +963,41 @@ void SymtabSection::finalizeContents() {
symbols.push_back({sym, strx});
};
+ std::function<void(Symbol *)> localSymbolsHandler;
+ switch (config->localSymbolsPresence) {
+ case SymtabPresence::All:
+ localSymbolsHandler = [&](Symbol *sym) { addSymbol(localSymbols, sym); };
+ break;
+ case SymtabPresence::None:
+ localSymbolsHandler = [&](Symbol *) { /* Do nothing*/ };
+ break;
+ case SymtabPresence::SelectivelyIncluded:
+ localSymbolsHandler = [&](Symbol *sym) {
+ if (config->localSymbolPatterns.match(sym->getName()))
+ addSymbol(localSymbols, sym);
+ };
+ break;
+ case SymtabPresence::SelectivelyExcluded:
+ localSymbolsHandler = [&](Symbol *sym) {
+ if (!config->localSymbolPatterns.match(sym->getName()))
+ addSymbol(localSymbols, sym);
+ };
+ break;
+ }
+
// Local symbols aren't in the SymbolTable, so we walk the list of object
// files to gather them.
- for (const InputFile *file : inputFiles) {
- if (auto *objFile = dyn_cast<ObjFile>(file)) {
- for (Symbol *sym : objFile->symbols) {
- if (auto *defined = dyn_cast_or_null<Defined>(sym)) {
- if (defined->isExternal() || !defined->isLive() ||
- !defined->includeInSymtab)
- continue;
- addSymbol(localSymbols, sym);
+ // But if `-x` is set, then we don't need to.
+ if (config->localSymbolsPresence != SymtabPresence::None) {
+ for (const InputFile *file : inputFiles) {
+ if (auto *objFile = dyn_cast<ObjFile>(file)) {
+ for (Symbol *sym : objFile->symbols) {
+ if (auto *defined = dyn_cast_or_null<Defined>(sym)) {
+ if (defined->isExternal() || !defined->isLive() ||
+ !defined->includeInSymtab)
+ continue;
+ localSymbolsHandler(sym);
+ }
}
}
}
@@ -981,7 +1006,7 @@ void SymtabSection::finalizeContents() {
// __dyld_private is a local symbol too. It's linker-created and doesn't
// exist in any object file.
if (Defined *dyldPrivate = in.stubHelper->dyldPrivate)
- addSymbol(localSymbols, dyldPrivate);
+ localSymbolsHandler(dyldPrivate);
for (Symbol *sym : symtab->getSymbols()) {
if (!sym->isLive())
@@ -991,7 +1016,7 @@ void SymtabSection::finalizeContents() {
continue;
assert(defined->isExternal());
if (defined->privateExtern)
- addSymbol(localSymbols, defined);
+ localSymbolsHandler(defined);
else
addSymbol(externalSymbols, defined);
} else if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
diff --git a/lld/test/MachO/local-symbol-output.s b/lld/test/MachO/local-symbol-output.s
new file mode 100644
index 0000000000000..3fd9458c00a54
--- /dev/null
+++ b/lld/test/MachO/local-symbol-output.s
@@ -0,0 +1,141 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/main.s -o %t/main.o
+
+## Check that -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
+## can't be used at the same time.
+# RUN: not %lld %t/main.o -o /dev/null \
+# RUN: -non_global_symbols_no_strip_list %t/foo.txt \
+# RUN: -non_global_symbols_strip_list %t/foo.txt 2>&1 | \
+# RUN: FileCheck --check-prefix=CONFLICT %s
+
+# CONFLICT: error: cannot use both -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
+
+## Check that -x causes none of the local symbols to be emitted.
+# RUN: %lld %t/main.o -x -o %t/no_local.out
+# RUN: llvm-nm %t/no_local.out | FileCheck --check-prefix NO_LOCAL %s
+
+# NO_LOCAL-NOT: t _foo
+# NO_LOCAL-NOT: t _bar
+# NO_LOCAL-NOT: t _baz
+# NO_LOCAL: T _main
+
+## Check that when using -x with -non_global_symbols_no_strip_list, whichever appears
+## last in the command line arg list will take precedence.
+# RUN: %lld %t/main.o -x -non_global_symbols_no_strip_list %t/foo.txt -o %t/x_then_no_strip.out
+# RUN: llvm-nm %t/x_then_no_strip.out | FileCheck --check-prefix X-NO-STRIP %s
+
+# RUN: %lld %t/main.o -non_global_symbols_no_strip_list %t/foo.txt -x -o %t/no_strip_then_x.out
+# RUN: llvm-nm %t/no_strip_then_x.out | FileCheck --check-prefix NO_LOCAL %s
+
+# X-NO-STRIP-NOT: t _bar
+# X-NO-STRIP-DAG: t _foo
+# X-NO-STRIP-DAG: T _main
+
+## Check that -non_global_symbols_no_strip_list can be specified more than once
+## (The final no-strip list is the union of all these)
+# RUN: %lld %t/main.o -o %t/no_strip_multi.out \
+# RUN: -non_global_symbols_no_strip_list %t/foo.txt \
+# RUN: -non_global_symbols_no_strip_list %t/bar.txt
+# RUN: llvm-nm %t/no_strip_multi.out | FileCheck --check-prefix NO-STRIP-MULTI %s
+
+# NO-STRIP-MULTI-NOT: t _baz
+# NO-STRIP-MULTI-DAG: t _foo
+# NO-STRIP-MULTI-DAG: t _bar
+# NO-STRIP-MULTI-DAG: T _main
+
+## Check that when using -x with -non_global_symbols_strip_list, whichever appears
+## last in the command line arg list will take precedence.
+# RUN: %lld %t/main.o -x -non_global_symbols_strip_list %t/foo.txt -o %t/x_then_strip.out
+# RUN: llvm-nm %t/x_then_strip.out | FileCheck --check-prefix X-STRIP %s
+
+# RUN: %lld %t/main.o -non_global_symbols_strip_list %t/foo.txt -x -o %t/strip_then_x.out
+# RUN: llvm-nm %t/no_strip_then_x.out | FileCheck --check-prefix NO_LOCAL %s
+
+# X-STRIP-NOT: t _foo
+# X-STRIP-DAG: t _bar
+# X-STRIP-DAG: t _baz
+# X-STRIP-DAG: T _main
+
+## Check that -non_global_symbols_strip_list can be specified more than once
+## (The final strip list is the union of all these)
+# RUN: %lld %t/main.o -o %t/strip_multi.out \
+# RUN: -non_global_symbols_strip_list %t/foo.txt \
+# RUN: -non_global_symbols_strip_list %t/bar.txt
+# RUN: llvm-nm %t/strip_multi.out | FileCheck --check-prefix STRIP-MULTI %s
+
+# STRIP-MULTI-NOT: t _foo
+# STRIP-MULTI-NOT: t _bar
+# STRIP-MULTI-DAG: t _baz
+# STRIP-MULTI-DAG: T _main
+
+## Test interactions with exported_symbol.
+# RUN: %lld %t/main.o -o %t/strip_all_export_one.out \
+# RUN: -x -exported_symbol _foo \
+# RUN: -undefined dynamic_lookup
+# RUN: llvm-nm %t/strip_all_export_one.out | FileCheck --check-prefix STRIP-EXP %s
+
+# STRIP-EXP: U _foo
+# STRIP-EXP-EMPTY:
+
+## Test interactions of -x and -non_global_symbols_strip_list with unexported_symbol.
+# RUN: %lld %t/main.o -o %t/strip_x_unexport_one.out \
+# RUN: -x -unexported_symbol _globby \
+# RUN: -undefined dynamic_lookup
+
+# RUN: %lld %t/main.o -o %t/strip_all_unexport_one.out \
+# RUN: -non_global_symbols_strip_list %t/globby.txt \
+# RUN: -non_global_symbols_strip_list %t/foo.txt \
+# RUN: -non_global_symbols_strip_list %t/bar.txt \
+# RUN: -unexported_symbol _globby \
+# RUN: -undefined dynamic_lookup
+
+# RUN: llvm-nm %t/strip_x_unexport_one.out | FileCheck --check-prefix STRIP-UNEXP %s
+# RUN: llvm-nm %t/strip_all_unexport_one.out | FileCheck --check-prefix STRIP-UNEXP %s
+
+## -unexported_symbol made _globby a local, therefore it should be stripped by -x too
+# STRIP-UNEXP: T __mh_execute_header
+# STRIP-UNEXP-DAG: T _main
+# STRIP-UNEXP-EMPTY:
+
+## Test interactions of -non_global_symbols_strip_list and unexported_symbol.
+# RUN: %lld %t/main.o -undefined dynamic_lookup -o %t/no_strip_unexport.out \
+# RUN: -non_global_symbols_no_strip_list %t/globby.txt \
+# RUN: -unexported_symbol _globby
+
+# RUN: llvm-nm %t/no_strip_unexport.out | FileCheck --check-prefix NOSTRIP-UNEXP %s
+
+# NOSTRIP-UNEXP: T __mh_execute_header
+# NOSTRIP-UNEXP-DAG: T _main
+# NOSTRIP-UNEXP-DAG: t _globby
+# NOSTRIP-UNEXP-EMPTY:
+
+#--- foo.txt
+_foo
+
+#--- bar.txt
+_bar
+
+#--- globby.txt
+_globby
+
+#--- main.s
+.globl _main
+.globl _globby
+
+_foo:
+ ret
+
+_bar:
+ ret
+
+_baz:
+ ret
+
+_main:
+ callq _foo
+ ret
+
+ _globby:
+ ret
\ No newline at end of file
More information about the llvm-commits
mailing list