diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 5e3b77637316..23627dd812db 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -99,6 +99,7 @@ struct Configuration { std::vector VersionDefinitions; std::vector Argv; std::vector AuxiliaryList; + std::vector FilterList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 10ad13f214d5..4630e110bcd8 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -259,6 +259,9 @@ static void checkOptions(opt::InputArgList &Args) { if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); + if (!Config->Shared && !Config->FilterList.empty()) + error("-F may not be used without -shared"); + if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); @@ -631,6 +634,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); Config->FatalWarnings = getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false); + Config->FilterList = getArgs(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false); Config->GdbIndex = Args.hasArg(OPT_gdb_index); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 29e14c530c6a..aa083b836825 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -104,6 +104,8 @@ def export_dynamic_symbol: S<"export-dynamic-symbol">, def fatal_warnings: F<"fatal-warnings">, HelpText<"Treat warnings as errors">; +def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">; + def fini: S<"fini">, MetaVarName<"">, HelpText<"Specify a finalizer function">; @@ -305,6 +307,7 @@ def alias_exclude_libs: J<"exclude-libs=">, Alias; def alias_export_dynamic_E: Flag<["-"], "E">, Alias; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias; +def alias_filter: Separate<["-"], "F">, Alias; def alias_fini_fini: J<"fini=">, Alias; def alias_format_b: S<"b">, Alias; def alias_hash_style_hash_style: J<"hash-style=">, Alias; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 4f380a1be2b8..8244606b3f9d 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1024,6 +1024,8 @@ DynamicSection::DynamicSection() template void DynamicSection::addEntries() { // Add strings to .dynstr early so that .dynstr's size will be // fixed early. + for (StringRef S : Config->FilterList) + add({DT_FILTER, InX::DynStrTab->addString(S)}); for (StringRef S : Config->AuxiliaryList) add({DT_AUXILIARY, InX::DynStrTab->addString(S)}); if (!Config->Rpath.empty()) diff --git a/lld/test/ELF/filter.s b/lld/test/ELF/filter.s new file mode 100644 index 000000000000..fa8e5267b18b --- /dev/null +++ b/lld/test/ELF/filter.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -shared -F foo.so -F boo.so -o %t1 +# RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s + +# Test alias. +# RUN: ld.lld %t.o -shared --filter=foo.so --filter=boo.so -o %t2 +# RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s + +# CHECK: DynamicSection [ +# CHECK-NEXT: Tag Type Name/Value +# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [foo.so] +# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [boo.so] + +# RUN: not ld.lld %t.o -F x -o %t 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: -F may not be used without -shared