Skip to content

[LLD][ELF][RISCV][Zicfilp][Zicfiss] Support -z <zicfilp-unlabeled|zicfilp-func-sig|zicfiss>-report-dynamic=<none|warning|error> options #144304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mylai-mtk
Copy link
Contributor

  • If -z zicfilp-unlabeled-report-dynamic=<warning|error> and the output object file has the ZICFILP-unlabeled feature, the linker warns/errors when any of the immediately linked dynamic object files (i.e. those explicitly passed to the linker) lacks the ZICFILP-unlabeled feature.
    • A similar report for checking relocatable files can be enabled by -z zicfilp-unlabeled-report=<warning|error>, which reports if any relocatable file lacks the ZICFILP-unlabeled feature.
    • -z zicfilp-unlabeled-report=<warning|error> implies -z zicfilp-unlabeled-report-dynamic=warning.
      • This is probably desired when the user wishes to enable ZICFILP-unlabeled.
      • The report level of dynamic object files is downgraded to warning in this implied case, since this allows the user to avoid rebuilding dynamic object files in the build environment.
  • This patch also implements the above mentioned -z xxx-report-dynamic option for the ZICFILP-func-sig/ZICFISS feature.

A similar option for the AArch64 GCS feature is implemented in #127787 .

…cfilp-func-sig|zicfiss>-report-dynamic=<none|warning|error>` options

+ If `-z zicfilp-unlabeled-report-dynamic=<warning|error>` and the output object file has the ZICFILP-unlabeled feature, the linker warns/errors when any of the immediately linked dynamic object files (i.e. those explicitly passed to the linker) lacks the ZICFILP-unlabeled feature.
  + A similar report for checking relocatable files can be enabled by `-z zicfilp-unlabeled-report=<warning|error>`, which reports if any relocatable file lacks the ZICFILP-unlabeled feature.
  + `-z zicfilp-unlabeled-report=<warning|error>` implies `-z zicfilp-unlabeled-report-dynamic=warning`.
    + This is probably desired when the user wishes to enable ZICFILP-unlabeled.
    + The report level of dynamic object files is downgraded to `warning` in this implied case, since this allows the user to avoid rebuilding dynamic object files in the build environment.
+ This patch also implements the above mentioned `-z xxx-report-dynamic` option for the ZICFILP-func-sig/ZICFISS feature.
@llvmbot
Copy link
Member

llvmbot commented Jun 16, 2025

@llvm/pr-subscribers-lld-elf

Author: Ming-Yi Lai (mylai-mtk)

Changes
  • If -z zicfilp-unlabeled-report-dynamic=&lt;warning|error&gt; and the output object file has the ZICFILP-unlabeled feature, the linker warns/errors when any of the immediately linked dynamic object files (i.e. those explicitly passed to the linker) lacks the ZICFILP-unlabeled feature.
    • A similar report for checking relocatable files can be enabled by -z zicfilp-unlabeled-report=&lt;warning|error&gt;, which reports if any relocatable file lacks the ZICFILP-unlabeled feature.
    • -z zicfilp-unlabeled-report=&lt;warning|error&gt; implies -z zicfilp-unlabeled-report-dynamic=warning.
      • This is probably desired when the user wishes to enable ZICFILP-unlabeled.
      • The report level of dynamic object files is downgraded to warning in this implied case, since this allows the user to avoid rebuilding dynamic object files in the build environment.
  • This patch also implements the above mentioned -z xxx-report-dynamic option for the ZICFILP-func-sig/ZICFISS feature.

A similar option for the AArch64 GCS feature is implemented in #127787 .


Patch is 20.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144304.diff

6 Files Affected:

  • (modified) lld/ELF/Config.h (+3)
  • (modified) lld/ELF/Driver.cpp (+118-30)
  • (modified) lld/ELF/InputFiles.cpp (+11-3)
  • (modified) lld/test/ELF/riscv-feature-zicfilp-func-sig.s (+16-1)
  • (modified) lld/test/ELF/riscv-feature-zicfilp-unlabeled.s (+16-1)
  • (modified) lld/test/ELF/riscv-feature-zicfiss.s (+16-1)
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 2b72d54ba410d..71c17016d92c0 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -259,8 +259,11 @@ struct Config {
   ReportPolicy zGcsReportDynamic = ReportPolicy::None;
   ReportPolicy zExecuteOnlyReport = ReportPolicy::None;
   ReportPolicy zZicfilpUnlabeledReport = ReportPolicy::None;
+  ReportPolicy zZicfilpUnlabeledReportDynamic = ReportPolicy::None;
   ReportPolicy zZicfilpFuncSigReport = ReportPolicy::None;
+  ReportPolicy zZicfilpFuncSigReportDynamic = ReportPolicy::None;
   ReportPolicy zZicfissReport = ReportPolicy::None;
+  ReportPolicy zZicfissReportDynamic = ReportPolicy::None;
   bool ltoBBAddrMap;
   llvm::StringRef ltoBasicBlockSections;
   std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 7e132a387a04d..0be98efafa3a1 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -425,11 +425,20 @@ static void checkOptions(Ctx &ctx) {
     if (ctx.arg.zZicfilpUnlabeledReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfilip-unlabeled-report is only supported on "
                         "RISC-V targets";
+    if (ctx.arg.zZicfilpUnlabeledReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfilip-unlabeled-report-dynamic is only supported"
+                        " on RISC-V targets";
     if (ctx.arg.zZicfilpFuncSigReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfilip-func-sig-report is only supported on "
                         "RISC-V targets";
+    if (ctx.arg.zZicfilpFuncSigReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfilip-func-sig-report-dynamic is only supported "
+                        "on RISC-V targets";
     if (ctx.arg.zZicfissReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfiss-report is only supported on RISC-V targets";
+    if (ctx.arg.zZicfissReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfiss-report-dynamic is only supported on RISC-V "
+                        "targets";
     if (ctx.arg.zZicfilp != ZicfilpPolicy::Implicit)
       ErrAlways(ctx) << "-z zicfilp is only supported on RISC-V targets";
     if (ctx.arg.zZicfiss != ZicfissPolicy::Implicit)
@@ -1686,45 +1695,84 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
       ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
   }
 
-  auto reports = {
-      std::make_pair("bti-report", &ctx.arg.zBtiReport),
-      std::make_pair("cet-report", &ctx.arg.zCetReport),
-      std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
-      std::make_pair("gcs-report", &ctx.arg.zGcsReport),
-      std::make_pair("gcs-report-dynamic", &ctx.arg.zGcsReportDynamic),
-      std::make_pair("pauth-report", &ctx.arg.zPauthReport),
-      std::make_pair("zicfilp-unlabeled-report",
-                     &ctx.arg.zZicfilpUnlabeledReport),
-      std::make_pair("zicfilp-func-sig-report", &ctx.arg.zZicfilpFuncSigReport),
-      std::make_pair("zicfiss-report", &ctx.arg.zZicfissReport)};
   bool hasGcsReportDynamic = false;
+  bool hasZicfilpUnlabeledReportDynamic = false;
+  bool hasZicfilpFuncSigReportDynamic = false;
+  bool hasZicfissReportDynamic = false;
+  struct ReportOptDesc {
+    const char *const name;
+    ReportPolicy &policy;
+    bool *const seen;
+
+    ReportOptDesc(const char *const name, ReportPolicy &policy, bool *seen)
+        : name(name), policy(policy), seen(seen) {}
+  };
+  const ReportOptDesc reports[] = {
+      {"bti-report", ctx.arg.zBtiReport, nullptr},
+      {"cet-report", ctx.arg.zCetReport, nullptr},
+      {"execute-only-report", ctx.arg.zExecuteOnlyReport, nullptr},
+      {"gcs-report", ctx.arg.zGcsReport, nullptr},
+      {"gcs-report-dynamic", ctx.arg.zGcsReportDynamic, &hasGcsReportDynamic},
+      {"pauth-report", ctx.arg.zPauthReport, nullptr},
+      {"zicfilp-unlabeled-report", ctx.arg.zZicfilpUnlabeledReport, nullptr},
+      {"zicfilp-unlabeled-report-dynamic",
+       ctx.arg.zZicfilpUnlabeledReportDynamic,
+       &hasZicfilpUnlabeledReportDynamic},
+      {"zicfilp-func-sig-report", ctx.arg.zZicfilpFuncSigReport, nullptr},
+      {"zicfilp-func-sig-report-dynamic", ctx.arg.zZicfilpFuncSigReportDynamic,
+       &hasZicfilpFuncSigReportDynamic},
+      {"zicfiss-report", ctx.arg.zZicfissReport, nullptr},
+      {"zicfiss-report-dynamic", ctx.arg.zZicfissReportDynamic,
+       &hasZicfissReportDynamic}};
   for (opt::Arg *arg : args.filtered(OPT_z)) {
     std::pair<StringRef, StringRef> option =
         StringRef(arg->getValue()).split('=');
-    for (auto reportArg : reports) {
-      if (option.first != reportArg.first)
+    for (const ReportOptDesc &desc : reports) {
+      if (option.first != desc.name)
         continue;
       arg->claim();
       if (option.second == "none")
-        *reportArg.second = ReportPolicy::None;
+        desc.policy = ReportPolicy::None;
       else if (option.second == "warning")
-        *reportArg.second = ReportPolicy::Warning;
+        desc.policy = ReportPolicy::Warning;
       else if (option.second == "error")
-        *reportArg.second = ReportPolicy::Error;
+        desc.policy = ReportPolicy::Error;
       else {
-        ErrAlways(ctx) << "unknown -z " << reportArg.first
+        ErrAlways(ctx) << "unknown -z " << desc.name
                        << "= value: " << option.second;
         continue;
       }
-      hasGcsReportDynamic |= option.first == "gcs-report-dynamic";
+      if (desc.seen)
+        *desc.seen = true;
     }
   }
 
-  // When -zgcs-report-dynamic is unspecified, it inherits -zgcs-report
-  // but is capped at warning to avoid needing to rebuild the shared library
-  // with GCS enabled.
-  if (!hasGcsReportDynamic && ctx.arg.zGcsReport != ReportPolicy::None)
-    ctx.arg.zGcsReportDynamic = ReportPolicy::Warning;
+  struct ReportDynamicOptDesc {
+    ReportPolicy &dynamicPolicy;
+    const ReportPolicy objectPolicy;
+    const bool seenDynamicPolicy;
+
+    ReportDynamicOptDesc(ReportPolicy &dynamicPolicy,
+                         const ReportPolicy objectPolicy,
+                         const bool seenDynamicPolicy)
+        : dynamicPolicy(dynamicPolicy), objectPolicy(objectPolicy),
+          seenDynamicPolicy(seenDynamicPolicy) {}
+  };
+  const ReportDynamicOptDesc reportDynamics[] = {
+      {ctx.arg.zGcsReportDynamic, ctx.arg.zGcsReport, hasGcsReportDynamic},
+      {ctx.arg.zZicfilpUnlabeledReportDynamic, ctx.arg.zZicfilpUnlabeledReport,
+       hasZicfilpUnlabeledReportDynamic},
+      {ctx.arg.zZicfilpFuncSigReportDynamic, ctx.arg.zZicfilpFuncSigReport,
+       hasZicfilpFuncSigReportDynamic},
+      {ctx.arg.zZicfissReportDynamic, ctx.arg.zZicfissReport,
+       hasZicfissReportDynamic}};
+  for (const ReportDynamicOptDesc &desc : reportDynamics) {
+    // When -z xxx-report-dynamic is unspecified, it inherits -z xxx-report
+    // but is capped at warning to avoid needing to rebuild the shared library
+    // with XXX enabled.
+    if (!desc.seenDynamicPolicy && desc.objectPolicy != ReportPolicy::None)
+      desc.dynamicPolicy = ReportPolicy::Warning;
+  }
 
   for (opt::Arg *arg : args.filtered(OPT_compress_sections)) {
     SmallVector<StringRef, 0> fields;
@@ -3066,13 +3114,15 @@ static void readSecurityNotes(Ctx &ctx) {
       ctx.arg.andFeatures &= ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
   }
 
-  // If we are utilising GCS at any stage, the sharedFiles should be checked to
-  // ensure they also support this feature. The gcs-report-dynamic option is
-  // used to indicate if the user wants information relating to this, and will
-  // be set depending on the user's input, or warning if gcs-report is set to
-  // either `warning` or `error`.
-  if (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
-    for (SharedFile *f : ctx.sharedFiles)
+  // If we are utilising AArch64 GCS/RISC-V ZICFILP-unlabeled/RISC-V
+  // ZICFILP-func-sig/RISC-V ZICFISS at any stage, the sharedFiles should be
+  // checked to ensure they also support this feature. The -z xxx-report-dynamic
+  // option is used to indicate if the user wants information relating to this,
+  // and will be set depending on the user's input, or warning if -z xxx-report
+  // is set to either `warning` or `error`.
+  for (SharedFile *f : ctx.sharedFiles) {
+    if (ctx.arg.emachine == EM_AARCH64 &&
+        (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS))
       reportUnless(ctx.arg.zGcsReportDynamic,
                    f->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
           << f
@@ -3081,6 +3131,44 @@ static void readSecurityNotes(Ctx &ctx) {
           << "dynamic loader might not enable GCS or refuse to load the "
              "program unless all shared library "
           << "dependencies have the GCS marking.";
+
+    if (ctx.arg.emachine == EM_RISCV) {
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+        reportUnless(ctx.arg.zZicfilpUnlabeledReportDynamic,
+                     f->andFeatures &
+                         GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+            << f << ": " << "ZICFILP-unlabeled"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFILP-unlabeled"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFILP-unlabeled" << " marking.";
+
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
+        reportUnless(ctx.arg.zZicfilpFuncSigReportDynamic,
+                     f->andFeatures &
+                         GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
+            << f << ": " << "ZICFILP-func-sig"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFILP-func-sig"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFILP-func-sig" << " marking.";
+
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
+        reportUnless(ctx.arg.zZicfissReportDynamic,
+                     f->andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
+            << f << ": " << "ZICFISS"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFISS"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFISS" << " marking.";
+    }
+  }
 }
 
 static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 71e72e7184b9f..08027408e1fd0 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1450,8 +1450,17 @@ std::vector<uint32_t> SharedFile::parseVerneed(const ELFFile<ELFT> &obj,
 // readGnuProperty, but we don't have the InputSection information.
 template <typename ELFT>
 void SharedFile::parseGnuAndFeatures(const ELFFile<ELFT> &obj) {
-  if (ctx.arg.emachine != EM_AARCH64)
+  unsigned featureAndType;
+  switch (ctx.arg.emachine) {
+  case EM_AARCH64:
+    featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
+    break;
+  case EM_RISCV:
+    featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
+    break;
+  default:
     return;
+  }
   const uint8_t *base = obj.base();
   auto phdrs = CHECK2(obj.program_headers(), this);
   for (auto phdr : phdrs) {
@@ -1463,8 +1472,7 @@ void SharedFile::parseGnuAndFeatures(const ELFFile<ELFT> &obj) {
       continue;
 
     ArrayRef<uint8_t> desc = note.getDesc(phdr.p_align);
-    parseGnuPropertyNote<ELFT>(ctx, *this, GNU_PROPERTY_AARCH64_FEATURE_1_AND,
-                               desc, base);
+    parseGnuPropertyNote<ELFT>(ctx, *this, featureAndType, desc, base);
   }
 }
 
diff --git a/lld/test/ELF/riscv-feature-zicfilp-func-sig.s b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
index c5818dd33978f..c2f3c064b19b5 100644
--- a/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
+++ b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
@@ -51,9 +51,24 @@
 # REPORT-WARN: warning: f2.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property
 # REPORT-ERROR: error: f3.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property
 
+## zicfilp-func-sig-report-dynamic should report any dynamic objects that does
+## not have the ZICFILP-func-sig property. This also ensures the inhertance from
+## zicfilp-func-sig-report is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report=warning -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report=error -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=none -z zicfilp=func-sig 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=warning -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=error -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfilp-func-sig-report-dynamic=error -z zicfilp=func-sig 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFILP-func-sig is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-func-sig or refuse to load the program unless all shared library dependencies have the ZICFILP-func-sig marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFILP-func-sig is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-func-sig or refuse to load the program unless all shared library dependencies have the ZICFILP-func-sig marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfilp-func-sig-report option should give an error
-# RUN: not ld.lld f2-s.o -z zicfilp-func-sig-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o -z zicfilp-func-sig-report=x -z zicfilp-func-sig-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfilp-func-sig-report= value: x
+# INVALID: error: unknown -z zicfilp-func-sig-report-dynamic= value: x
 
 ## ZICFILP-unlabeled and ZICFILP-func-sig should conflict with each other.
 # RUN: ld.lld f3-u.o -o out.override -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=FORCE-CONFLICT %s
diff --git a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
index 20491f057c8ed..f06b3db2f6c2b 100644
--- a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
+++ b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
@@ -53,10 +53,25 @@
 # REPORT-WARN: warning: f2.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
 # REPORT-ERROR: error: f3.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
 
+## zicfilp-unlabeled-report-dynamic should report any dynamic objects that does
+## not have the ZICFILP-unlabeled property. This also ensures the inhertance
+## from zicfilp-unlabeled-report is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report=warning -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report=error -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=none -z zicfilp=unlabeled 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=warning -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=error -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfilp-unlabeled-report-dynamic=error -z zicfilp=unlabeled 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFILP-unlabeled is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-unlabeled or refuse to load the program unless all shared library dependencies have the ZICFILP-unlabeled marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFILP-unlabeled is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-unlabeled or refuse to load the program unless all shared library dependencies have the ZICFILP-unlabeled marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfilp-unlabeled-report option should give an error
-# RUN: not ld.lld f2-s.o -z zicfilp=x -z zicfilp-unlabeled-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o -z zicfilp=x -z zicfilp-unlabeled-report=x -z zicfilp-unlabeled-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfilp= value: x
 # INVALID: error: unknown -z zicfilp-unlabeled-report= value: x
+# INVALID: error: unknown -z zicfilp-unlabeled-report-dynamic= value: x
 
 ## ZICFILP-unlabeled and ZICFILP-func-sig should conflict with each other
 # RUN: not ld.lld f1-c.o 2>&1 | FileCheck --check-prefix=CONFLICT %s
diff --git a/lld/test/ELF/riscv-feature-zicfiss.s b/lld/test/ELF/riscv-feature-zicfiss.s
index 7b208ddd9b8eb..e0b82f19054b8 100644
--- a/lld/test/ELF/riscv-feature-zicfiss.s
+++ b/lld/test/ELF/riscv-feature-zicfiss.s
@@ -48,10 +48,25 @@
 # REPORT-WARN: warning: f2.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
 # REPORT-ERROR: error: f3.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
 
+## zicfiss-report-dynamic should report any dynamic objects that does not have
+## the ZICFISS property. This also ensures the inhertance from zicfiss-report
+## is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report=warning -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report=error -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=none -z zicfiss=always 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=warning -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=error -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfiss-report-dynamic=error -z zicfiss=always 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFISS is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFISS or refuse to load the program unless all shared library dependencies have the ZICFISS marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFISS is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFISS or refuse to load the program unless all shared library dependencies have the ZICFISS marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfiss-report option should give an error
-# RUN: not ld.lld f2-s.o f3-s.o -z zicfiss=x -z zicfiss-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o f3-s.o -z zicfiss=x -z zicfiss-report=x -z zicfiss-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfiss= value: x
 # INVALID: error: un...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jun 16, 2025

@llvm/pr-subscribers-lld

Author: Ming-Yi Lai (mylai-mtk)

Changes
  • If -z zicfilp-unlabeled-report-dynamic=&lt;warning|error&gt; and the output object file has the ZICFILP-unlabeled feature, the linker warns/errors when any of the immediately linked dynamic object files (i.e. those explicitly passed to the linker) lacks the ZICFILP-unlabeled feature.
    • A similar report for checking relocatable files can be enabled by -z zicfilp-unlabeled-report=&lt;warning|error&gt;, which reports if any relocatable file lacks the ZICFILP-unlabeled feature.
    • -z zicfilp-unlabeled-report=&lt;warning|error&gt; implies -z zicfilp-unlabeled-report-dynamic=warning.
      • This is probably desired when the user wishes to enable ZICFILP-unlabeled.
      • The report level of dynamic object files is downgraded to warning in this implied case, since this allows the user to avoid rebuilding dynamic object files in the build environment.
  • This patch also implements the above mentioned -z xxx-report-dynamic option for the ZICFILP-func-sig/ZICFISS feature.

A similar option for the AArch64 GCS feature is implemented in #127787 .


Patch is 20.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144304.diff

6 Files Affected:

  • (modified) lld/ELF/Config.h (+3)
  • (modified) lld/ELF/Driver.cpp (+118-30)
  • (modified) lld/ELF/InputFiles.cpp (+11-3)
  • (modified) lld/test/ELF/riscv-feature-zicfilp-func-sig.s (+16-1)
  • (modified) lld/test/ELF/riscv-feature-zicfilp-unlabeled.s (+16-1)
  • (modified) lld/test/ELF/riscv-feature-zicfiss.s (+16-1)
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 2b72d54ba410d..71c17016d92c0 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -259,8 +259,11 @@ struct Config {
   ReportPolicy zGcsReportDynamic = ReportPolicy::None;
   ReportPolicy zExecuteOnlyReport = ReportPolicy::None;
   ReportPolicy zZicfilpUnlabeledReport = ReportPolicy::None;
+  ReportPolicy zZicfilpUnlabeledReportDynamic = ReportPolicy::None;
   ReportPolicy zZicfilpFuncSigReport = ReportPolicy::None;
+  ReportPolicy zZicfilpFuncSigReportDynamic = ReportPolicy::None;
   ReportPolicy zZicfissReport = ReportPolicy::None;
+  ReportPolicy zZicfissReportDynamic = ReportPolicy::None;
   bool ltoBBAddrMap;
   llvm::StringRef ltoBasicBlockSections;
   std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 7e132a387a04d..0be98efafa3a1 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -425,11 +425,20 @@ static void checkOptions(Ctx &ctx) {
     if (ctx.arg.zZicfilpUnlabeledReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfilip-unlabeled-report is only supported on "
                         "RISC-V targets";
+    if (ctx.arg.zZicfilpUnlabeledReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfilip-unlabeled-report-dynamic is only supported"
+                        " on RISC-V targets";
     if (ctx.arg.zZicfilpFuncSigReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfilip-func-sig-report is only supported on "
                         "RISC-V targets";
+    if (ctx.arg.zZicfilpFuncSigReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfilip-func-sig-report-dynamic is only supported "
+                        "on RISC-V targets";
     if (ctx.arg.zZicfissReport != ReportPolicy::None)
       ErrAlways(ctx) << "-z zicfiss-report is only supported on RISC-V targets";
+    if (ctx.arg.zZicfissReportDynamic != ReportPolicy::None)
+      ErrAlways(ctx) << "-z zicfiss-report-dynamic is only supported on RISC-V "
+                        "targets";
     if (ctx.arg.zZicfilp != ZicfilpPolicy::Implicit)
       ErrAlways(ctx) << "-z zicfilp is only supported on RISC-V targets";
     if (ctx.arg.zZicfiss != ZicfissPolicy::Implicit)
@@ -1686,45 +1695,84 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
       ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
   }
 
-  auto reports = {
-      std::make_pair("bti-report", &ctx.arg.zBtiReport),
-      std::make_pair("cet-report", &ctx.arg.zCetReport),
-      std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
-      std::make_pair("gcs-report", &ctx.arg.zGcsReport),
-      std::make_pair("gcs-report-dynamic", &ctx.arg.zGcsReportDynamic),
-      std::make_pair("pauth-report", &ctx.arg.zPauthReport),
-      std::make_pair("zicfilp-unlabeled-report",
-                     &ctx.arg.zZicfilpUnlabeledReport),
-      std::make_pair("zicfilp-func-sig-report", &ctx.arg.zZicfilpFuncSigReport),
-      std::make_pair("zicfiss-report", &ctx.arg.zZicfissReport)};
   bool hasGcsReportDynamic = false;
+  bool hasZicfilpUnlabeledReportDynamic = false;
+  bool hasZicfilpFuncSigReportDynamic = false;
+  bool hasZicfissReportDynamic = false;
+  struct ReportOptDesc {
+    const char *const name;
+    ReportPolicy &policy;
+    bool *const seen;
+
+    ReportOptDesc(const char *const name, ReportPolicy &policy, bool *seen)
+        : name(name), policy(policy), seen(seen) {}
+  };
+  const ReportOptDesc reports[] = {
+      {"bti-report", ctx.arg.zBtiReport, nullptr},
+      {"cet-report", ctx.arg.zCetReport, nullptr},
+      {"execute-only-report", ctx.arg.zExecuteOnlyReport, nullptr},
+      {"gcs-report", ctx.arg.zGcsReport, nullptr},
+      {"gcs-report-dynamic", ctx.arg.zGcsReportDynamic, &hasGcsReportDynamic},
+      {"pauth-report", ctx.arg.zPauthReport, nullptr},
+      {"zicfilp-unlabeled-report", ctx.arg.zZicfilpUnlabeledReport, nullptr},
+      {"zicfilp-unlabeled-report-dynamic",
+       ctx.arg.zZicfilpUnlabeledReportDynamic,
+       &hasZicfilpUnlabeledReportDynamic},
+      {"zicfilp-func-sig-report", ctx.arg.zZicfilpFuncSigReport, nullptr},
+      {"zicfilp-func-sig-report-dynamic", ctx.arg.zZicfilpFuncSigReportDynamic,
+       &hasZicfilpFuncSigReportDynamic},
+      {"zicfiss-report", ctx.arg.zZicfissReport, nullptr},
+      {"zicfiss-report-dynamic", ctx.arg.zZicfissReportDynamic,
+       &hasZicfissReportDynamic}};
   for (opt::Arg *arg : args.filtered(OPT_z)) {
     std::pair<StringRef, StringRef> option =
         StringRef(arg->getValue()).split('=');
-    for (auto reportArg : reports) {
-      if (option.first != reportArg.first)
+    for (const ReportOptDesc &desc : reports) {
+      if (option.first != desc.name)
         continue;
       arg->claim();
       if (option.second == "none")
-        *reportArg.second = ReportPolicy::None;
+        desc.policy = ReportPolicy::None;
       else if (option.second == "warning")
-        *reportArg.second = ReportPolicy::Warning;
+        desc.policy = ReportPolicy::Warning;
       else if (option.second == "error")
-        *reportArg.second = ReportPolicy::Error;
+        desc.policy = ReportPolicy::Error;
       else {
-        ErrAlways(ctx) << "unknown -z " << reportArg.first
+        ErrAlways(ctx) << "unknown -z " << desc.name
                        << "= value: " << option.second;
         continue;
       }
-      hasGcsReportDynamic |= option.first == "gcs-report-dynamic";
+      if (desc.seen)
+        *desc.seen = true;
     }
   }
 
-  // When -zgcs-report-dynamic is unspecified, it inherits -zgcs-report
-  // but is capped at warning to avoid needing to rebuild the shared library
-  // with GCS enabled.
-  if (!hasGcsReportDynamic && ctx.arg.zGcsReport != ReportPolicy::None)
-    ctx.arg.zGcsReportDynamic = ReportPolicy::Warning;
+  struct ReportDynamicOptDesc {
+    ReportPolicy &dynamicPolicy;
+    const ReportPolicy objectPolicy;
+    const bool seenDynamicPolicy;
+
+    ReportDynamicOptDesc(ReportPolicy &dynamicPolicy,
+                         const ReportPolicy objectPolicy,
+                         const bool seenDynamicPolicy)
+        : dynamicPolicy(dynamicPolicy), objectPolicy(objectPolicy),
+          seenDynamicPolicy(seenDynamicPolicy) {}
+  };
+  const ReportDynamicOptDesc reportDynamics[] = {
+      {ctx.arg.zGcsReportDynamic, ctx.arg.zGcsReport, hasGcsReportDynamic},
+      {ctx.arg.zZicfilpUnlabeledReportDynamic, ctx.arg.zZicfilpUnlabeledReport,
+       hasZicfilpUnlabeledReportDynamic},
+      {ctx.arg.zZicfilpFuncSigReportDynamic, ctx.arg.zZicfilpFuncSigReport,
+       hasZicfilpFuncSigReportDynamic},
+      {ctx.arg.zZicfissReportDynamic, ctx.arg.zZicfissReport,
+       hasZicfissReportDynamic}};
+  for (const ReportDynamicOptDesc &desc : reportDynamics) {
+    // When -z xxx-report-dynamic is unspecified, it inherits -z xxx-report
+    // but is capped at warning to avoid needing to rebuild the shared library
+    // with XXX enabled.
+    if (!desc.seenDynamicPolicy && desc.objectPolicy != ReportPolicy::None)
+      desc.dynamicPolicy = ReportPolicy::Warning;
+  }
 
   for (opt::Arg *arg : args.filtered(OPT_compress_sections)) {
     SmallVector<StringRef, 0> fields;
@@ -3066,13 +3114,15 @@ static void readSecurityNotes(Ctx &ctx) {
       ctx.arg.andFeatures &= ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
   }
 
-  // If we are utilising GCS at any stage, the sharedFiles should be checked to
-  // ensure they also support this feature. The gcs-report-dynamic option is
-  // used to indicate if the user wants information relating to this, and will
-  // be set depending on the user's input, or warning if gcs-report is set to
-  // either `warning` or `error`.
-  if (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
-    for (SharedFile *f : ctx.sharedFiles)
+  // If we are utilising AArch64 GCS/RISC-V ZICFILP-unlabeled/RISC-V
+  // ZICFILP-func-sig/RISC-V ZICFISS at any stage, the sharedFiles should be
+  // checked to ensure they also support this feature. The -z xxx-report-dynamic
+  // option is used to indicate if the user wants information relating to this,
+  // and will be set depending on the user's input, or warning if -z xxx-report
+  // is set to either `warning` or `error`.
+  for (SharedFile *f : ctx.sharedFiles) {
+    if (ctx.arg.emachine == EM_AARCH64 &&
+        (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS))
       reportUnless(ctx.arg.zGcsReportDynamic,
                    f->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
           << f
@@ -3081,6 +3131,44 @@ static void readSecurityNotes(Ctx &ctx) {
           << "dynamic loader might not enable GCS or refuse to load the "
              "program unless all shared library "
           << "dependencies have the GCS marking.";
+
+    if (ctx.arg.emachine == EM_RISCV) {
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+        reportUnless(ctx.arg.zZicfilpUnlabeledReportDynamic,
+                     f->andFeatures &
+                         GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+            << f << ": " << "ZICFILP-unlabeled"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFILP-unlabeled"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFILP-unlabeled" << " marking.";
+
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
+        reportUnless(ctx.arg.zZicfilpFuncSigReportDynamic,
+                     f->andFeatures &
+                         GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
+            << f << ": " << "ZICFILP-func-sig"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFILP-func-sig"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFILP-func-sig" << " marking.";
+
+      if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
+        reportUnless(ctx.arg.zZicfissReportDynamic,
+                     f->andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
+            << f << ": " << "ZICFISS"
+            << " is enabled, but this shared library lacks the necessary "
+               "property note. The dynamic loader might not enable "
+            << "ZICFISS"
+            << " or refuse to load the program unless all shared library "
+               "dependencies have the "
+            << "ZICFISS" << " marking.";
+    }
+  }
 }
 
 static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 71e72e7184b9f..08027408e1fd0 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1450,8 +1450,17 @@ std::vector<uint32_t> SharedFile::parseVerneed(const ELFFile<ELFT> &obj,
 // readGnuProperty, but we don't have the InputSection information.
 template <typename ELFT>
 void SharedFile::parseGnuAndFeatures(const ELFFile<ELFT> &obj) {
-  if (ctx.arg.emachine != EM_AARCH64)
+  unsigned featureAndType;
+  switch (ctx.arg.emachine) {
+  case EM_AARCH64:
+    featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
+    break;
+  case EM_RISCV:
+    featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
+    break;
+  default:
     return;
+  }
   const uint8_t *base = obj.base();
   auto phdrs = CHECK2(obj.program_headers(), this);
   for (auto phdr : phdrs) {
@@ -1463,8 +1472,7 @@ void SharedFile::parseGnuAndFeatures(const ELFFile<ELFT> &obj) {
       continue;
 
     ArrayRef<uint8_t> desc = note.getDesc(phdr.p_align);
-    parseGnuPropertyNote<ELFT>(ctx, *this, GNU_PROPERTY_AARCH64_FEATURE_1_AND,
-                               desc, base);
+    parseGnuPropertyNote<ELFT>(ctx, *this, featureAndType, desc, base);
   }
 }
 
diff --git a/lld/test/ELF/riscv-feature-zicfilp-func-sig.s b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
index c5818dd33978f..c2f3c064b19b5 100644
--- a/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
+++ b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
@@ -51,9 +51,24 @@
 # REPORT-WARN: warning: f2.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property
 # REPORT-ERROR: error: f3.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property
 
+## zicfilp-func-sig-report-dynamic should report any dynamic objects that does
+## not have the ZICFILP-func-sig property. This also ensures the inhertance from
+## zicfilp-func-sig-report is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report=warning -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report=error -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=none -z zicfilp=func-sig 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=warning -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-func-sig-report-dynamic=error -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfilp-func-sig-report-dynamic=error -z zicfilp=func-sig 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFILP-func-sig is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-func-sig or refuse to load the program unless all shared library dependencies have the ZICFILP-func-sig marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFILP-func-sig is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-func-sig or refuse to load the program unless all shared library dependencies have the ZICFILP-func-sig marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfilp-func-sig-report option should give an error
-# RUN: not ld.lld f2-s.o -z zicfilp-func-sig-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o -z zicfilp-func-sig-report=x -z zicfilp-func-sig-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfilp-func-sig-report= value: x
+# INVALID: error: unknown -z zicfilp-func-sig-report-dynamic= value: x
 
 ## ZICFILP-unlabeled and ZICFILP-func-sig should conflict with each other.
 # RUN: ld.lld f3-u.o -o out.override -z zicfilp=func-sig 2>&1 | FileCheck --check-prefix=FORCE-CONFLICT %s
diff --git a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
index 20491f057c8ed..f06b3db2f6c2b 100644
--- a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
+++ b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
@@ -53,10 +53,25 @@
 # REPORT-WARN: warning: f2.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
 # REPORT-ERROR: error: f3.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
 
+## zicfilp-unlabeled-report-dynamic should report any dynamic objects that does
+## not have the ZICFILP-unlabeled property. This also ensures the inhertance
+## from zicfilp-unlabeled-report is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report=warning -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report=error -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=none -z zicfilp=unlabeled 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=warning -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfilp-unlabeled-report-dynamic=error -z zicfilp=unlabeled 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfilp-unlabeled-report-dynamic=error -z zicfilp=unlabeled 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFILP-unlabeled is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-unlabeled or refuse to load the program unless all shared library dependencies have the ZICFILP-unlabeled marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFILP-unlabeled is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFILP-unlabeled or refuse to load the program unless all shared library dependencies have the ZICFILP-unlabeled marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfilp-unlabeled-report option should give an error
-# RUN: not ld.lld f2-s.o -z zicfilp=x -z zicfilp-unlabeled-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o -z zicfilp=x -z zicfilp-unlabeled-report=x -z zicfilp-unlabeled-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfilp= value: x
 # INVALID: error: unknown -z zicfilp-unlabeled-report= value: x
+# INVALID: error: unknown -z zicfilp-unlabeled-report-dynamic= value: x
 
 ## ZICFILP-unlabeled and ZICFILP-func-sig should conflict with each other
 # RUN: not ld.lld f1-c.o 2>&1 | FileCheck --check-prefix=CONFLICT %s
diff --git a/lld/test/ELF/riscv-feature-zicfiss.s b/lld/test/ELF/riscv-feature-zicfiss.s
index 7b208ddd9b8eb..e0b82f19054b8 100644
--- a/lld/test/ELF/riscv-feature-zicfiss.s
+++ b/lld/test/ELF/riscv-feature-zicfiss.s
@@ -48,10 +48,25 @@
 # REPORT-WARN: warning: f2.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
 # REPORT-ERROR: error: f3.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
 
+## zicfiss-report-dynamic should report any dynamic objects that does not have
+## the ZICFISS property. This also ensures the inhertance from zicfiss-report
+## is working correctly.
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report=warning -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report=error -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=none -z zicfiss=always 2>&1 | count 0
+# RUN: ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=warning -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
+# RUN: not ld.lld f1-s.o f3-s.o out.no.so out.force.so -z zicfiss-report-dynamic=error -z zicfiss=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
+# RUN: ld.lld f1-s.o f3-s.o out.force.so -z zicfiss-report-dynamic=error -z zicfiss=always 2>&1 | count 0
+# REPORT-WARN-DYNAMIC: warning: out.no.so: ZICFISS is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFISS or refuse to load the program unless all shared library dependencies have the ZICFISS marking.
+# REPORT-WARN-DYNAMIC-NOT: {{.}}
+# REPORT-ERROR-DYNAMIC: error: out.no.so: ZICFISS is enabled, but this shared library lacks the necessary property note. The dynamic loader might not enable ZICFISS or refuse to load the program unless all shared library dependencies have the ZICFISS marking.
+# REPORT-ERROR-DYNAMIC-NOT: error:
+
 ## An invalid -z zicfiss-report option should give an error
-# RUN: not ld.lld f2-s.o f3-s.o -z zicfiss=x -z zicfiss-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld f2-s.o f3-s.o -z zicfiss=x -z zicfiss-report=x -z zicfiss-report-dynamic=x 2>&1 | FileCheck --check-prefix=INVALID %s
 # INVALID: error: unknown -z zicfiss= value: x
 # INVALID: error: un...
[truncated]

Copy link

github-actions bot commented Jun 16, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants