[ELF] Refactor the way we handle -plugin-opt= (GCC collect2 or clang LTO related options)

GCC collect2 passes several options to the linker even if LTO is not used
(note, lld does not support GCC LTO). The lto-wrapper may be a relative
path (especially during development, when gcc is in a build directory), e.g.

  -plugin-opt=relative/path/to/lto-wrapper

We need to ignore such options, which are currently interpreted by
cl::ParseCommandLineOptions() and will fail with `error: --plugin-opt: ld.lld: Unknown command line argument 'relative/path/to/lto-wrapper'`
because the path is apparently not an option registered by an `llvm:🆑:opt`.

See lto-plugin-ignore.s for how we interpret various -plugin-opt= options now.

Reviewed By: grimar, tejohnson

Differential Revision: https://reviews.llvm.org/D78158
This commit is contained in:
Fangrui Song 2020-04-14 14:17:29 -07:00
parent 7a6aaf9b23
commit cd5d5ce235
3 changed files with 46 additions and 14 deletions

View File

@ -1035,8 +1035,16 @@ static void readConfigs(opt::InputArgList &args) {
parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
arg->getSpelling());
for (auto *arg : args.filtered(OPT_plugin_opt))
parseClangOption(arg->getValue(), arg->getSpelling());
for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq_minus))
parseClangOption(std::string("-") + arg->getValue(), arg->getSpelling());
// GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or
// relative path. Just ignore. If not ended with "lto-wrapper", consider it an
// unsupported LLVMgold.so option and error.
for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq))
if (!StringRef(arg->getValue()).endswith("lto-wrapper"))
error(arg->getSpelling() + ": unknown plugin option '" + arg->getValue() +
"'");
// Parse -mllvm options.
for (auto *arg : args.filtered(OPT_mllvm))

View File

@ -504,7 +504,6 @@ def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
HelpText<"Include hotness information in the optimization remarks file">;
def opt_remarks_format: Separate<["--"], "opt-remarks-format">,
HelpText<"The format used for serializing remarks (default: YAML)">;
defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
def save_temps: F<"save-temps">;
def lto_basicblock_sections: J<"lto-basicblock-sections=">,
HelpText<"Enable basic block sections for LTO">;
@ -571,10 +570,17 @@ def: J<"plugin-opt=thinlto-prefix-replace=">,
// --version output.
defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
def plugin_opt_slash: J<"plugin-opt=/">;
def plugin_opt_eq_minus: J<"plugin-opt=-">,
HelpText<"Specify an LLVM option for compatibility with LLVMgold.so">;
def: J<"plugin-opt=thinlto">;
// Ignore GCC collect2 LTO plugin related options. Note that we don't support
// GCC LTO, but GCC collect2 passes these options even in non-LTO mode.
def: J<"plugin-opt=-fresolution=">;
def: J<"plugin-opt=-pass-through=">;
// This may be either an unhandled LLVMgold.so feature or GCC passed
// -plugin-opt=path/to/{liblto_plugin.so,lto-wrapper}
def plugin_opt_eq : J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def: F<"detect-odr-violations">;

View File

@ -1,10 +1,28 @@
# REQUIRES: x86
## Test we ignore some LTO related options from clang/GCC collect2.
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld %t -plugin-opt=/foo/bar -plugin-opt=-fresolution=zed \
# RUN: -plugin-opt=-pass-through=-lgcc -plugin-opt=-function-sections \
# RUN: -plugin-opt=-data-sections -plugin-opt=thinlto -o /dev/null
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
# RUN: not ld.lld %t -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s
# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-abc'
# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-xyz'
## GCC collect2 passes several LTO related options to the linker even if -flto is not used.
## We need to ignore them. Note that the lto-wrapper path can be relative.
# RUN: ld.lld %t.o -o /dev/null \
# RUN: -plugin path/to/liblto_plugin.so \
# RUN: -plugin-opt=/path/to/lto-wrapper \
# RUN: -plugin-opt=relative/path/to/lto-wrapper \
# RUN: -plugin-opt=-fresolution=zed \
# RUN: -plugin-opt=-pass-through=-lgcc \
# RUN: -plugin-opt=-pass-through=-lgcc_eh \
# RUN: -plugin-opt=-pass-through=-lc
## Clang LTO passes several options to the linker, which are intended to be consumed by
## LLVMgold.so. We need to ignore them.
# RUN: ld.lld %t.o -o /dev/null -plugin /path/to/LLVMgold.so -plugin-opt=thinlto
## Other -plugin-opt=- prefixed options are passed through to cl::ParseCommandLineOptions.
# RUN: not ld.lld %t.o -o /dev/null -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s
# CHECK: ld.lld: error: -plugin-opt=-: ld.lld{{.*}}: Unknown command line argument '-abc'
# CHECK: ld.lld: error: -plugin-opt=-: ld.lld{{.*}}: Unknown command line argument '-xyz'
## Error if the option is an unhandled LLVMgold.so feature.
# RUN: not ld.lld %t.o -o /dev/null -plugin-opt=LLVMgold-feature 2>&1 | FileCheck --check-prefix=GOLD %s
# GOLD: ld.lld: error: -plugin-opt=: unknown plugin option 'LLVMgold-feature'