Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -228,6 +228,8 @@ bool warnMissingEntry; bool warnSymbolOrdering; bool writeAddends; + StringRef zBtiReport; + StringRef zCetReport; bool zCombreloc; bool zCopyreloc; bool zForceBti; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -368,6 +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) { + if (config->zCetReport != "none") + error("-z cet-report only supported on X86 and X86_64"); } } @@ -455,6 +462,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="); @@ -982,6 +990,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); @@ -1160,6 +1173,8 @@ config->warnSymbolOrdering = args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); config->whyExtract = args.getLastArgValue(OPT_why_extract); + config->zBtiReport = "none"; + config->zCetReport = "none"; config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true); config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true); config->zForceBti = hasZOption(args, "force-bti"); @@ -1217,6 +1232,23 @@ error(errPrefix + toString(pat.takeError())); } + auto reports = {std::make_pair("bti-report", &config->zBtiReport), + std::make_pair("cet-report", &config->zCetReport)}; + for (auto reportArg : reports) { + for (opt::Arg *arg : args.filtered(OPT_z)) { + std::pair option = + StringRef(arg->getValue()).split('='); + 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('='); @@ -2119,6 +2151,17 @@ symtab->wrap(w.sym, w.real, w.wrap); } +static void checkAndReportMissingFeature(llvm::StringRef config, + uint32_t features, uint32_t mask, + const std::string &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 @@ -2135,14 +2178,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)) { Index: lld/docs/ld.lld.1 =================================================================== --- lld/docs/ld.lld.1 +++ lld/docs/ld.lld.1 @@ -686,6 +686,14 @@ .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. 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. 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 Index: lld/test/ELF/aarch64-bti-pac-cli-error.s =================================================================== --- lld/test/ELF/aarch64-bti-pac-cli-error.s +++ lld/test/ELF/aarch64-bti-pac-cli-error.s @@ -1,12 +1,13 @@ # 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 .globl start start: ret Index: lld/test/ELF/aarch64-feature-bti.s =================================================================== --- lld/test/ELF/aarch64-feature-bti.s +++ 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 Index: lld/test/ELF/i386-feature-cet.s =================================================================== --- lld/test/ELF/i386-feature-cet.s +++ lld/test/ELF/i386-feature-cet.s @@ -23,6 +23,14 @@ # RUN: | FileCheck --check-prefix=WARN %s # WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# RUN: ld.lld -e func1 %t.o %t3.o -o %t.wanr -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 + +# RUN: not ld.lld -e func1 %t.o %t3.o -o %t.err -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 + # RUN: ld.lld -e func1 %t.o %t4.o -o %t # RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s Index: lld/test/ELF/x86-64-feature-cet.s =================================================================== --- lld/test/ELF/x86-64-feature-cet.s +++ lld/test/ELF/x86-64-feature-cet.s @@ -23,6 +23,21 @@ # RUN: | FileCheck --check-prefix=WARN %s # WARN: {{.*}}.o: -z force-ibt: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# RUN: ld.lld -e func1 %t.o %t3.o -o %t -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-NOT: {{.*}}.o: -z force-ibt: + +# RUN: ld.lld -e func1 %t.o %t3.o -o %t.warn -z cet-report=warning 2>&1 \ +# RUN: | FileCheck --check-prefix=CE_REPORT_WARN %s +# CE_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CE_REPORT_WARN: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property + +# RUN: not ld.lld -e func1 %t.o %t3.o -o %t.err -z cet-report=error 2>&1 \ +# RUN: | FileCheck --check-prefix=CE_REPORT_ERROR %s +# CE_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_IBT property +# CE_REPORT_ERROR: {{.*}}.o: -z cet-report: file does not have GNU_PROPERTY_X86_FEATURE_1_SHSTK property + # RUN: ld.lld -e func1 %t.o %t4.o -o %t # RUN: llvm-readelf -n %t | FileCheck --check-prefix=NOSHSTK %s