diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -128,6 +128,8 @@ llvm::StringRef thinLTOCacheDir; llvm::StringRef thinLTOIndexOnlyArg; llvm::StringRef whyExtract; + StringRef zBtiReport = "none"; + StringRef zCetReport = "none"; llvm::StringRef ltoBasicBlockSections; std::pair thinLTOObjectSuffixReplace; std::pair thinLTOPrefixReplace; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -368,7 +368,13 @@ error("-z pac-plt only supported on AArch64"); if (config->zForceBti) error("-z force-bti only supported on AArch64"); + if (config->zBtiReport != "none") + error("-z bti-report only supported on AArch64"); } + + if (config->emachine != EM_386 && config->emachine != EM_X86_64 && + config->zCetReport != "none") + error("-z cet-report only supported on X86 and X86_64"); } static const char *getReproduceOption(opt::InputArgList &args) { @@ -455,6 +461,7 @@ s == "rela" || s == "relro" || s == "retpolineplt" || s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" || s == "wxneeded" || s.startswith("common-page-size=") || + s.startswith("bti-report=") || s.startswith("cet-report=") || s.startswith("dead-reloc-in-nonalloc=") || s.startswith("max-page-size=") || s.startswith("stack-size=") || s.startswith("start-stop-visibility="); @@ -970,6 +977,11 @@ error(msg + ": " + StringRef(err).trim()); } +// Checks the parameter of the bti-report and cet-report options. +static bool isValidReportString(StringRef arg) { + return arg == "none" || arg == "warning" || arg == "error"; +} + // Initializes Config members by the command line options. static void readConfigs(opt::InputArgList &args) { errorHandler().verbose = args.hasArg(OPT_verbose); @@ -1203,6 +1215,23 @@ error(errPrefix + toString(pat.takeError())); } + auto reports = {std::make_pair("bti-report", &config->zBtiReport), + std::make_pair("cet-report", &config->zCetReport)}; + for (opt::Arg *arg : args.filtered(OPT_z)) { + std::pair option = + StringRef(arg->getValue()).split('='); + for (auto reportArg : reports) { + if (option.first != reportArg.first) + continue; + if (!isValidReportString(option.second)) { + error(Twine("-z ") + reportArg.first + "= parameter " + option.second + + " is not recognized"); + continue; + } + *reportArg.second = option.second; + } + } + for (opt::Arg *arg : args.filtered(OPT_z)) { std::pair option = StringRef(arg->getValue()).split('='); @@ -2103,6 +2132,16 @@ symtab->wrap(w.sym, w.real, w.wrap); } +static void checkAndReportMissingFeature(StringRef config, uint32_t features, + uint32_t mask, const Twine &report) { + if (!(features & mask)) { + if (config == "error") + error(report); + else if (config == "warning") + warn(report); + } +} + // To enable CET (x86's hardware-assited control flow enforcement), each // source file must be compiled with -fcf-protection. Object files compiled // with the flag contain feature flags indicating that they are compatible @@ -2119,14 +2158,32 @@ uint32_t ret = -1; for (InputFile *f : objectFiles) { uint32_t features = cast>(f)->andFeatures; + + checkAndReportMissingFeature( + config->zBtiReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_BTI, + toString(f) + ": -z bti-report: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"); + + checkAndReportMissingFeature( + config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT, + toString(f) + ": -z cet-report: file does not have " + "GNU_PROPERTY_X86_FEATURE_1_IBT property"); + + checkAndReportMissingFeature( + config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_SHSTK, + toString(f) + ": -z cet-report: file does not have " + "GNU_PROPERTY_X86_FEATURE_1_SHSTK property"); + if (config->zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { - warn(toString(f) + ": -z force-bti: file does not have " - "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"); features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + if (config->zBtiReport == "none") + warn(toString(f) + ": -z force-bti: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"); } else if (config->zForceIbt && !(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) { - warn(toString(f) + ": -z force-ibt: file does not have " - "GNU_PROPERTY_X86_FEATURE_1_IBT property"); + if (config->zCetReport == "none") + warn(toString(f) + ": -z force-ibt: file does not have " + "GNU_PROPERTY_X86_FEATURE_1_IBT property"); features |= GNU_PROPERTY_X86_FEATURE_1_IBT; } if (config->zPacPlt && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) { diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -702,6 +702,16 @@ .Dv PT_GNU_STACK segment. .Pp +.It Cm bti-report Ns = Ns Ar [none|warning|error] +Specify how to report the missing GNU_PROPERTY_AARCH64_FEATURE_1_BTI property. +.Cm none +is the default, linker will not report the missing property otherwise will be reported as a warning or an error. +.Pp +.It Cm cet-report Ns = Ns Ar [none|warning|error] +Specify how to report the missing GNU_PROPERTY_X86_FEATURE_1_IBT or GNU_PROPERTY_X86_FEATURE_1_SHSTK properties. +.Cm none +is the default, linker will not report the missing property otherwise will be reported as a warning or an error. +.Pp .It Cm force-bti Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property. .Pp diff --git a/lld/test/ELF/aarch64-bti-pac-cli-error.s b/lld/test/ELF/aarch64-bti-pac-cli-error.s --- a/lld/test/ELF/aarch64-bti-pac-cli-error.s +++ b/lld/test/ELF/aarch64-bti-pac-cli-error.s @@ -1,12 +1,18 @@ # REQUIRES: x86 # RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj -o %t.o %s -# RUN: not ld.lld -z pac-plt -z force-bti %t.o -o /dev/null 2>&1 | FileCheck %s +# RUN: not ld.lld -z pac-plt -z force-bti -z bti-report=error %t.o -o /dev/null 2>&1 | FileCheck %s # -## Check that we error if -z pac-plt and -z force-bti are used when target is not +## Check that we error if -z pac-plt, -z force-bti and -z bti-report=error are used when target is not ## aarch64 # CHECK: error: -z pac-plt only supported on AArch64 # CHECK-NEXT: error: -z force-bti only supported on AArch64 +# CHECK-NEXT: error: -z bti-report only supported on AArch64 + +# RUN: not ld.lld -z bti-report=something %t.o -o /dev/null 2>&1 | \ +# RUN: FileCheck --check-prefix=REPORT_INVALID %s +# REPORT_INVALID: error: -z bti-report= parameter something is not recognized +# REPORT_INVALID-EMPTY: .globl start start: ret diff --git a/lld/test/ELF/aarch64-feature-bti.s b/lld/test/ELF/aarch64-feature-bti.s --- a/lld/test/ELF/aarch64-feature-bti.s +++ b/lld/test/ELF/aarch64-feature-bti.s @@ -187,9 +187,11 @@ ## from the file without the .note.gnu.property. # RUN: ld.lld %t.o %t2.o -z force-bti %t.so -o %tforcebti.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s +# RUN: not ld.lld %t.o %t2.o -z force-bti -z bti-report=error %t.so -o %tfailifnotbti.exe 2>&1 | FileCheck --check-prefix=BTI_REPORT-ERROR %s # FORCE-WARN: aarch64-feature-bti.s.tmp2.o: -z force-bti: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property - +# BTI_REPORT-ERROR: aarch64-feature-bti.s.tmp2.o: -z bti-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property +# BTI_REPORT-ERROR-EMPTY: # RUN: llvm-readelf -n %tforcebti.exe | FileCheck --check-prefix=BTIPROP %s # RUN: llvm-readelf --dynamic-table %tforcebti.exe | FileCheck --check-prefix BTIDYN %s diff --git a/lld/test/ELF/i386-feature-cet.s b/lld/test/ELF/i386-feature-cet.s --- a/lld/test/ELF/i386-feature-cet.s +++ b/lld/test/ELF/i386-feature-cet.s @@ -23,6 +23,23 @@ # RUN: | FileCheck --check-prefix=WARN %s # WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=something 2>&1 \ +# RUN: | FileCheck --check-prefix=REPORT_INVALID %s +# REPORT_INVALID: error: -z cet-report= parameter something is not recognized +# REPORT_INVALID-EMPTY: + +# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=warning 2>&1 \ +# RUN: | FileCheck --check-prefix=CET_REPORT_WARN %s +# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property +# CET_REPORT_WARN-EMPTY: + +# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=error 2>&1 \ +# RUN: | FileCheck --check-prefix=CET_REPORT_ERROR %s +# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property +# CET_REPORT_ERROR-EMPTY: + # RUN: ld.lld -e func1 %t.o %t4.o -o %t # RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s diff --git a/lld/test/ELF/x86-64-feature-cet.s b/lld/test/ELF/x86-64-feature-cet.s --- a/lld/test/ELF/x86-64-feature-cet.s +++ b/lld/test/ELF/x86-64-feature-cet.s @@ -23,6 +23,29 @@ # RUN: | FileCheck --check-prefix=WARN %s # WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# RUN:not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=something 2>&1 \ +# RUN: | FileCheck --check-prefix=REPORT_INVALID %s +# REPORT_INVALID: error: -z cet-report= parameter something is not recognized +# REPORT_INVALID-EMPTY: + +# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z force-ibt -z cet-report=warning 2>&1 \ +# RUN: | FileCheck --check-prefix=REPORT_FORCE %s +# REPORT_FORCE: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# REPORT_FORCE: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property +# REPORT_FORCE-EMPTY: + +# RUN: ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=warning 2>&1 \ +# RUN: | FileCheck --check-prefix=CET_REPORT_WARN %s +# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CET_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property +# CET_REPORT_WARN-EMPTY: + +# RUN: not ld.lld -e func1 %t.o %t3.o -o /dev/null -z cet-report=error 2>&1 \ +# RUN: | FileCheck --check-prefix=CET_REPORT_ERROR %s +# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CET_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property +# CET_REPORT_ERROR-EMPTY: + # RUN: ld.lld -e func1 %t.o %t4.o -o %t # RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s