[lld] [lld][AArch64] Add support for GCS (PR #90732)

John Brawn via llvm-commits llvm-commits at lists.llvm.org
Thu May 16 03:14:33 PDT 2024


https://github.com/john-brawn-arm updated https://github.com/llvm/llvm-project/pull/90732

>From 386e93630a3aa2846f50e88732004cddf358bce4 Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Wed, 13 Dec 2023 16:22:23 +0000
Subject: [PATCH 1/5] [lld][AArch64] Add support for GCS

This adds the -z gcs and -z gcs-report options, which behave similarly
to -z shtk and -z cet-report, except that -z gcs accepts a parameter:
 * -z gcs=implicit is the default behaviour, where the GCS bit is
   inferred from the input objects.
 * -z gcs=never clears the GCS bit, ignoring the input objects.
 * -z gcs=always sets the GCS bit, ignoring the input objects.
 * -z gcs is the same as -z gcs=always.

This is so that there's a means of explicitly disabling GCS even when
all input objects have the GCS bit set.
---
 lld/ELF/Config.h                        |  2 +
 lld/ELF/Driver.cpp                      | 38 +++++++++++++-
 lld/test/ELF/Inputs/aarch64-func2-gcs.s | 19 +++++++
 lld/test/ELF/Inputs/aarch64-func3-gcs.s | 16 ++++++
 lld/test/ELF/aarch64-feature-gcs.s      | 66 +++++++++++++++++++++++++
 5 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 lld/test/ELF/Inputs/aarch64-func2-gcs.s
 create mode 100644 lld/test/ELF/Inputs/aarch64-func3-gcs.s
 create mode 100644 lld/test/ELF/aarch64-feature-gcs.s

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 33bfa42b0fcbf..8279cd4aafc16 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -188,6 +188,8 @@ struct Config {
   StringRef zBtiReport = "none";
   StringRef zCetReport = "none";
   StringRef zPauthReport = "none";
+  StringRef zGcsReport = "none";
+  StringRef zGcs = "implicit";
   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 a5b47f020f872..b5dab029f110e 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -466,6 +466,10 @@ static void checkOptions() {
       error("-z bti-report only supported on AArch64");
     if (config->zPauthReport != "none")
       error("-z pauth-report only supported on AArch64");
+    if (config->zGcsReport != "none")
+      error("-z gcs-report only supported on AArch64");
+    if (config->zGcs != "implicit")
+      error("-z gcs only supported on AArch64");
   }
 
   if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
@@ -560,6 +564,25 @@ static uint8_t getZStartStopVisibility(opt::InputArgList &args) {
   return ret;
 }
 
+static StringRef getZGcs(opt::InputArgList &args) {
+  StringRef ret = "implicit";
+  for (auto *arg : args.filtered(OPT_z)) {
+    std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
+    if (kv.first == "gcs") {
+      arg->claim();
+      if (kv.second == "implicit" || kv.second == "always" ||
+          kv.second == "never")
+        ret = kv.second;
+      else if (StringRef(arg->getValue()) == "gcs")
+        // -z gcs is the same as -z gcs=always
+        ret = "always";
+      else
+        error("unknown -z gcs= value: " + StringRef(kv.second));
+    }
+  }
+  return ret;
+}
+
 // Report a warning for an unknown -z option.
 static void checkZOptions(opt::InputArgList &args) {
   // This function is called before getTarget(), when certain options are not
@@ -1436,6 +1459,7 @@ static void readConfigs(opt::InputArgList &args) {
   config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
   config->zForceBti = hasZOption(args, "force-bti");
   config->zForceIbt = hasZOption(args, "force-ibt");
+  config->zGcs = getZGcs(args);
   config->zGlobal = hasZOption(args, "global");
   config->zGnustack = getZGnuStack(args);
   config->zHazardplt = hasZOption(args, "hazardplt");
@@ -1508,7 +1532,8 @@ static void readConfigs(opt::InputArgList &args) {
 
   auto reports = {std::make_pair("bti-report", &config->zBtiReport),
                   std::make_pair("cet-report", &config->zCetReport),
-                  std::make_pair("pauth-report", &config->zPauthReport)};
+                  std::make_pair("pauth-report", &config->zPauthReport),
+                  std::make_pair("gcs-report", &config->zGcsReport)};
   for (opt::Arg *arg : args.filtered(OPT_z)) {
     std::pair<StringRef, StringRef> option =
         StringRef(arg->getValue()).split('=');
@@ -2667,6 +2692,11 @@ static void readSecurityNotes() {
         toString(f) + ": -z bti-report: file does not have "
                       "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
 
+    checkAndReportMissingFeature(
+        config->zGcsReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_GCS,
+        toString(f) + ": -z gcs-report: file does not have "
+                      "GNU_PROPERTY_AARCH64_FEATURE_1_GCS property");
+
     checkAndReportMissingFeature(
         config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT,
         toString(f) + ": -z cet-report: file does not have "
@@ -2719,6 +2749,12 @@ static void readSecurityNotes() {
   // Force enable Shadow Stack.
   if (config->zShstk)
     config->andFeatures |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+
+  // Force enable/disable GCS
+  if (config->zGcs == "always")
+    config->andFeatures |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+  else if (config->zGcs == "never")
+    config->andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
 }
 
 static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
diff --git a/lld/test/ELF/Inputs/aarch64-func2-gcs.s b/lld/test/ELF/Inputs/aarch64-func2-gcs.s
new file mode 100644
index 0000000000000..4e7e95dcaff7c
--- /dev/null
+++ b/lld/test/ELF/Inputs/aarch64-func2-gcs.s
@@ -0,0 +1,19 @@
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
+.long 0
+
+.text
+.globl func2
+.type func2, at function
+func2:
+  .globl func3
+  .type func3, @function
+  bl func3
+  ret
diff --git a/lld/test/ELF/Inputs/aarch64-func3-gcs.s b/lld/test/ELF/Inputs/aarch64-func3-gcs.s
new file mode 100644
index 0000000000000..28460338822cd
--- /dev/null
+++ b/lld/test/ELF/Inputs/aarch64-func3-gcs.s
@@ -0,0 +1,16 @@
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
+.long 0
+
+.text
+.globl func3
+.type func3, at function
+func3:
+  ret
diff --git a/lld/test/ELF/aarch64-feature-gcs.s b/lld/test/ELF/aarch64-feature-gcs.s
new file mode 100644
index 0000000000000..31cb3b4cdee9c
--- /dev/null
+++ b/lld/test/ELF/aarch64-feature-gcs.s
@@ -0,0 +1,66 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2-gcs.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-gcs.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %t2no.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t3no.o
+
+# GCS should be enabled when it's enabled in all inputs or when it's forced on.
+
+# RUN: ld.lld %t1.o %t2.o %t3.o --shared -o %t.exe
+# RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix GCS %s
+# RUN: ld.lld %t1.o %t3.o --shared -o %t.so
+# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix GCS %s
+# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tforce.exe -z gcs
+# RUN: llvm-readelf -n %tforce.exe | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: ld.lld %t2.o %t3no.o --shared -o %tforce.so -z gcs=always
+# RUN: llvm-readelf -n %tforce.so | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: ld.lld %t2.o %t3no.o --shared -o %tforce2.so -z gcs=never -z gcs=always
+# RUN: llvm-readelf -n %tforce2.so | FileCheck --allow-empty --check-prefix GCS %s
+
+# GCS: Properties:    aarch64 feature: GCS
+
+# GCS should not be enabled if it's not enabled in at least one input, and we
+# should warn or error when using the report option.
+
+# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tno.exe
+# RUN: llvm-readelf -n %tno.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld %t2.o %t3no.o --shared -o %tno.so
+# RUN: llvm-readelf -n %tno.so | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tno.exe -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: llvm-readelf -n %tno.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: not ld.lld %t2.o %t3no.o --shared -o %tno.so -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+
+# NOGCS-NOT: Properties
+# REPORT-WARN: warning: {{.*}}tmp2no.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+# REPORT-ERROR: error: {{.*}}tmp3no.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+
+# GCS should be disabled with gcs=never, even if GCS is present in all inputs.
+
+# RUN: ld.lld %t1.o %t2.o %t3.o -z gcs=never --shared -o %tnever.exe
+# RUN: llvm-readelf -n %tnever.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld %t1.o %t2.o %t3.o -z gcs=always -z gcs=never --shared -o %tnever2.exe
+# RUN: llvm-readelf -n %tnever2.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+
+# An invalid gcs option should give an error
+# RUN: not ld.lld %t1.o %t2.o %t3.o -z gcs=nonsense -o %tinvalid.exe 2>&1 | FileCheck --check-prefix=INVALID %s
+
+# INVALID: error: unknown -z gcs= value: nonsense
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
+.long 0
+
+.text
+.globl _start
+.type func1,%function
+func1:
+  bl func2
+  ret

>From 97fab30c2aea52111899395ab63d53341c208482 Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Thu, 2 May 2024 12:01:46 +0100
Subject: [PATCH 2/5] Adjust test according to review comments

---
 lld/test/ELF/Inputs/aarch64-func2-gcs.s |  19 ----
 lld/test/ELF/Inputs/aarch64-func3-gcs.s |  16 ---
 lld/test/ELF/aarch64-feature-gcs.s      | 134 +++++++++++++++++-------
 3 files changed, 98 insertions(+), 71 deletions(-)
 delete mode 100644 lld/test/ELF/Inputs/aarch64-func2-gcs.s
 delete mode 100644 lld/test/ELF/Inputs/aarch64-func3-gcs.s

diff --git a/lld/test/ELF/Inputs/aarch64-func2-gcs.s b/lld/test/ELF/Inputs/aarch64-func2-gcs.s
deleted file mode 100644
index 4e7e95dcaff7c..0000000000000
--- a/lld/test/ELF/Inputs/aarch64-func2-gcs.s
+++ /dev/null
@@ -1,19 +0,0 @@
-.section ".note.gnu.property", "a"
-.long 4
-.long 0x10
-.long 0x5
-.asciz "GNU"
-
-.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
-.long 4
-.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
-.long 0
-
-.text
-.globl func2
-.type func2, at function
-func2:
-  .globl func3
-  .type func3, @function
-  bl func3
-  ret
diff --git a/lld/test/ELF/Inputs/aarch64-func3-gcs.s b/lld/test/ELF/Inputs/aarch64-func3-gcs.s
deleted file mode 100644
index 28460338822cd..0000000000000
--- a/lld/test/ELF/Inputs/aarch64-func3-gcs.s
+++ /dev/null
@@ -1,16 +0,0 @@
-.section ".note.gnu.property", "a"
-.long 4
-.long 0x10
-.long 0x5
-.asciz "GNU"
-
-.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
-.long 4
-.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
-.long 0
-
-.text
-.globl func3
-.type func3, at function
-func3:
-  ret
diff --git a/lld/test/ELF/aarch64-feature-gcs.s b/lld/test/ELF/aarch64-feature-gcs.s
index 31cb3b4cdee9c..1c6759bd7ba26 100644
--- a/lld/test/ELF/aarch64-feature-gcs.s
+++ b/lld/test/ELF/aarch64-feature-gcs.s
@@ -1,52 +1,54 @@
 # REQUIRES: aarch64
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2-gcs.s -o %t2.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-gcs.s -o %t3.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %t2no.o
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t3no.o
-
-# GCS should be enabled when it's enabled in all inputs or when it's forced on.
-
-# RUN: ld.lld %t1.o %t2.o %t3.o --shared -o %t.exe
-# RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix GCS %s
-# RUN: ld.lld %t1.o %t3.o --shared -o %t.so
-# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix GCS %s
-# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tforce.exe -z gcs
-# RUN: llvm-readelf -n %tforce.exe | FileCheck --allow-empty --check-prefix GCS %s
-# RUN: ld.lld %t2.o %t3no.o --shared -o %tforce.so -z gcs=always
-# RUN: llvm-readelf -n %tforce.so | FileCheck --allow-empty --check-prefix GCS %s
-# RUN: ld.lld %t2.o %t3no.o --shared -o %tforce2.so -z gcs=never -z gcs=always
-# RUN: llvm-readelf -n %tforce2.so | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func1.s -o func1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2.s -o func2.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2-gcs.s -o func2-gcs.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func3.s -o func3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func3-gcs.s -o func3-gcs.o
+
+## GCS should be enabled when it's enabled in all inputs or when it's forced on.
+
+# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o --shared -o gcs.exe
+# RUN: llvm-readelf -n gcs.exe | FileCheck --check-prefix GCS %s
+# RUN: ld.lld func1.o func3-gcs.o --shared -o gcs.so
+# RUN: llvm-readelf -n gcs.so | FileCheck --check-prefix GCS %s
+# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o force-gcs.exe -z gcs
+# RUN: llvm-readelf -n force-gcs.exe | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs.so -z gcs=always
+# RUN: llvm-readelf -n force-gcs.so | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs2.so -z gcs=never -z gcs=always
+# RUN: llvm-readelf -n force-gcs2.so | FileCheck --allow-empty --check-prefix GCS %s
 
 # GCS: Properties:    aarch64 feature: GCS
 
-# GCS should not be enabled if it's not enabled in at least one input, and we
-# should warn or error when using the report option.
+## GCS should not be enabled if it's not enabled in at least one input, and we
+## should warn or error when using the report option.
 
-# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tno.exe
-# RUN: llvm-readelf -n %tno.exe | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: ld.lld %t2.o %t3no.o --shared -o %tno.so
-# RUN: llvm-readelf -n %tno.so | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: ld.lld %t1.o %t2no.o %t3.o --shared -o %tno.exe -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
-# RUN: llvm-readelf -n %tno.exe | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: not ld.lld %t2.o %t3no.o --shared -o %tno.so -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o no-gcs.exe
+# RUN: llvm-readelf -n no-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func2-gcs.o func3.o --shared -o no-gcs.so
+# RUN: llvm-readelf -n no-gcs.so | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o no-gcs.exe -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: llvm-readelf -n no-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: not ld.lld func2-gcs.o func3.o --shared -o no-gcs.so -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
 
 # NOGCS-NOT: Properties
-# REPORT-WARN: warning: {{.*}}tmp2no.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
-# REPORT-ERROR: error: {{.*}}tmp3no.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+# REPORT-WARN: warning: func2.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+# REPORT-ERROR: error: func3.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
 
-# GCS should be disabled with gcs=never, even if GCS is present in all inputs.
+## GCS should be disabled with gcs=never, even if GCS is present in all inputs.
 
-# RUN: ld.lld %t1.o %t2.o %t3.o -z gcs=never --shared -o %tnever.exe
-# RUN: llvm-readelf -n %tnever.exe | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: ld.lld %t1.o %t2.o %t3.o -z gcs=always -z gcs=never --shared -o %tnever2.exe
-# RUN: llvm-readelf -n %tnever2.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=never --shared -o never-gcs.exe
+# RUN: llvm-readelf -n never-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=always -z gcs=never --shared -o never-gcs2.exe
+# RUN: llvm-readelf -n never-gcs2.exe | FileCheck --allow-empty --check-prefix NOGCS %s
 
-# An invalid gcs option should give an error
-# RUN: not ld.lld %t1.o %t2.o %t3.o -z gcs=nonsense -o %tinvalid.exe 2>&1 | FileCheck --check-prefix=INVALID %s
+## An invalid gcs option should give an error
+# RUN: not ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=nonsense -o invalid.exe 2>&1 | FileCheck --check-prefix=INVALID %s
 
 # INVALID: error: unknown -z gcs= value: nonsense
 
+#--- func1.s
 .section ".note.gnu.property", "a"
 .long 4
 .long 0x10
@@ -64,3 +66,63 @@
 func1:
   bl func2
   ret
+
+#--- func2.s
+
+.text
+.globl func2
+.type func2, at function
+func2:
+  .globl func3
+  .type func3, @function
+  bl func3
+  ret
+
+#--- func2-gcs.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
+.long 0
+
+.text
+.globl func2
+.type func2, at function
+func2:
+  .globl func3
+  .type func3, @function
+  bl func3
+  ret
+
+#--- func3.s
+
+.text
+.globl func3
+.type func3, at function
+func3:
+  ret
+
+#--- func3-gcs.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 4          // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
+.long 0
+
+.text
+.globl func3
+.type func3, at function
+func3:
+  ret

>From 65d4211e356af9776f4207b61b8ddf42b14d3286 Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Tue, 7 May 2024 14:25:37 +0100
Subject: [PATCH 3/5] Adjust tests, minor adjustment to Driver.cpp

---
 lld/ELF/Driver.cpp                 |  6 ++--
 lld/test/ELF/aarch64-feature-gcs.s | 53 +++++++++++++++++-------------
 2 files changed, 34 insertions(+), 25 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index b5dab029f110e..fcb674db6cfae 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -577,7 +577,7 @@ static StringRef getZGcs(opt::InputArgList &args) {
         // -z gcs is the same as -z gcs=always
         ret = "always";
       else
-        error("unknown -z gcs= value: " + StringRef(kv.second));
+        error("unknown -z gcs= value: " + kv.second);
     }
   }
   return ret;
@@ -1532,8 +1532,8 @@ static void readConfigs(opt::InputArgList &args) {
 
   auto reports = {std::make_pair("bti-report", &config->zBtiReport),
                   std::make_pair("cet-report", &config->zCetReport),
-                  std::make_pair("pauth-report", &config->zPauthReport),
-                  std::make_pair("gcs-report", &config->zGcsReport)};
+                  std::make_pair("gcs-report", &config->zGcsReport),
+                  std::make_pair("pauth-report", &config->zPauthReport)};
   for (opt::Arg *arg : args.filtered(OPT_z)) {
     std::pair<StringRef, StringRef> option =
         StringRef(arg->getValue()).split('=');
diff --git a/lld/test/ELF/aarch64-feature-gcs.s b/lld/test/ELF/aarch64-feature-gcs.s
index 1c6759bd7ba26..de6045e38fe25 100644
--- a/lld/test/ELF/aarch64-feature-gcs.s
+++ b/lld/test/ELF/aarch64-feature-gcs.s
@@ -1,6 +1,6 @@
 # REQUIRES: aarch64
 # RUN: rm -rf %t && split-file %s %t && cd %t
-# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func1.s -o func1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func1-gcs.s -o func1-gcs.o
 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2.s -o func2.o
 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2-gcs.s -o func2-gcs.o
 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func3.s -o func3.o
@@ -8,12 +8,12 @@
 
 ## GCS should be enabled when it's enabled in all inputs or when it's forced on.
 
-# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o --shared -o gcs.exe
-# RUN: llvm-readelf -n gcs.exe | FileCheck --check-prefix GCS %s
-# RUN: ld.lld func1.o func3-gcs.o --shared -o gcs.so
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o gcs
+# RUN: llvm-readelf -n gcs | FileCheck --check-prefix GCS %s
+# RUN: ld.lld func1-gcs.o func3-gcs.o --shared -o gcs.so
 # RUN: llvm-readelf -n gcs.so | FileCheck --check-prefix GCS %s
-# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o force-gcs.exe -z gcs
-# RUN: llvm-readelf -n force-gcs.exe | FileCheck --allow-empty --check-prefix GCS %s
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o force-gcs -z gcs
+# RUN: llvm-readelf -n force-gcs | FileCheck --allow-empty --check-prefix GCS %s
 # RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs.so -z gcs=always
 # RUN: llvm-readelf -n force-gcs.so | FileCheck --allow-empty --check-prefix GCS %s
 # RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs2.so -z gcs=never -z gcs=always
@@ -21,34 +21,43 @@
 
 # GCS: Properties:    aarch64 feature: GCS
 
-## GCS should not be enabled if it's not enabled in at least one input, and we
-## should warn or error when using the report option.
+## GCS should not be enabled if it's not enabled in at least one input.
 
-# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o no-gcs.exe
-# RUN: llvm-readelf -n no-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o no-gcs
+# RUN: llvm-readelf -n no-gcs | FileCheck --allow-empty --check-prefix NOGCS %s
 # RUN: ld.lld func2-gcs.o func3.o --shared -o no-gcs.so
-# RUN: llvm-readelf -n no-gcs.so | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: ld.lld func1.o func2.o func3-gcs.o --shared -o no-gcs.exe -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
-# RUN: llvm-readelf -n no-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: not ld.lld func2-gcs.o func3.o --shared -o no-gcs.so -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
 
 # NOGCS-NOT: Properties
-# REPORT-WARN: warning: func2.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
-# REPORT-ERROR: error: func3.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
 
 ## GCS should be disabled with gcs=never, even if GCS is present in all inputs.
 
-# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=never --shared -o never-gcs.exe
-# RUN: llvm-readelf -n never-gcs.exe | FileCheck --allow-empty --check-prefix NOGCS %s
-# RUN: ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=always -z gcs=never --shared -o never-gcs2.exe
-# RUN: llvm-readelf -n never-gcs2.exe | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=never -o never-gcs
+# RUN: llvm-readelf -n never-gcs | FileCheck --allow-empty --check-prefix NOGCS %s
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=always -z gcs=never -o never-gcs2
+# RUN: llvm-readelf -n never-gcs2 | FileCheck --allow-empty --check-prefix NOGCS %s
+
+## gcs-report should report any input files that don't have the gcs property.
+
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=never 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error -z gcs=never 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning | FileCheck --allow-empty --check-prefix=REPORT-NONE %s
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=always | FileCheck --allow-empty --check-prefix=REPORT-NONE %s
+# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=never | FileCheck --allow-empty --check-prefix=REPORT-NONE %s
+
+# REPORT-WARN: warning: func2.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+# REPORT-ERROR: error: func3.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
+# REPORT-NONE-NOT: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
 
 ## An invalid gcs option should give an error
-# RUN: not ld.lld func1.o func2-gcs.o func3-gcs.o -z gcs=nonsense -o invalid.exe 2>&1 | FileCheck --check-prefix=INVALID %s
+# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=nonsense 2>&1 | FileCheck --check-prefix=INVALID %s
 
 # INVALID: error: unknown -z gcs= value: nonsense
 
-#--- func1.s
+#--- func1-gcs.s
 .section ".note.gnu.property", "a"
 .long 4
 .long 0x10

>From 7889711c5adc51ea24c98572450b59be4a571940 Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Tue, 7 May 2024 16:09:50 +0100
Subject: [PATCH 4/5] Change zGcs type to GcsPolicy

---
 lld/ELF/Config.h   |  5 ++++-
 lld/ELF/Driver.cpp | 21 ++++++++++++---------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 8279cd4aafc16..cac6bc77db29b 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -102,6 +102,9 @@ enum class GnuStackKind { None, Exec, NoExec };
 // For --lto=
 enum LtoKind : uint8_t {UnifiedThin, UnifiedRegular, Default};
 
+// For -z gcs=
+enum class GcsPolicy { Implicit, Never, Always };
+
 struct SymbolVersion {
   llvm::StringRef name;
   bool isExternCpp;
@@ -189,7 +192,6 @@ struct Config {
   StringRef zCetReport = "none";
   StringRef zPauthReport = "none";
   StringRef zGcsReport = "none";
-  StringRef zGcs = "implicit";
   bool ltoBBAddrMap;
   llvm::StringRef ltoBasicBlockSections;
   std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
@@ -341,6 +343,7 @@ struct Config {
   UnresolvedPolicy unresolvedSymbols;
   UnresolvedPolicy unresolvedSymbolsInShlib;
   Target2Policy target2;
+  GcsPolicy zGcs;
   bool power10Stubs;
   ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
   BuildIdKind buildId = BuildIdKind::None;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index fcb674db6cfae..ed36994afe2a8 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -468,7 +468,7 @@ static void checkOptions() {
       error("-z pauth-report only supported on AArch64");
     if (config->zGcsReport != "none")
       error("-z gcs-report only supported on AArch64");
-    if (config->zGcs != "implicit")
+    if (config->zGcs != GcsPolicy::Implicit)
       error("-z gcs only supported on AArch64");
   }
 
@@ -564,18 +564,21 @@ static uint8_t getZStartStopVisibility(opt::InputArgList &args) {
   return ret;
 }
 
-static StringRef getZGcs(opt::InputArgList &args) {
-  StringRef ret = "implicit";
+static GcsPolicy getZGcs(opt::InputArgList &args) {
+  GcsPolicy ret = GcsPolicy::Implicit;
   for (auto *arg : args.filtered(OPT_z)) {
     std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
     if (kv.first == "gcs") {
       arg->claim();
-      if (kv.second == "implicit" || kv.second == "always" ||
-          kv.second == "never")
-        ret = kv.second;
+      if (kv.second == "implicit")
+        ret = GcsPolicy::Implicit;
+      else if (kv.second == "never")
+        ret = GcsPolicy::Never;
+      else if (kv.second == "always")
+        ret = GcsPolicy::Always;
       else if (StringRef(arg->getValue()) == "gcs")
         // -z gcs is the same as -z gcs=always
-        ret = "always";
+        ret = GcsPolicy::Always;
       else
         error("unknown -z gcs= value: " + kv.second);
     }
@@ -2751,9 +2754,9 @@ static void readSecurityNotes() {
     config->andFeatures |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
 
   // Force enable/disable GCS
-  if (config->zGcs == "always")
+  if (config->zGcs == GcsPolicy::Always)
     config->andFeatures |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
-  else if (config->zGcs == "never")
+  else if (config->zGcs == GcsPolicy::Never)
     config->andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
 }
 

>From 6e77ff40b7585826bccabe609f60902daa530730 Mon Sep 17 00:00:00 2001
From: John Brawn <john.brawn at arm.com>
Date: Tue, 14 May 2024 11:33:16 +0100
Subject: [PATCH 5/5] Remove gcs alias

---
 lld/ELF/Driver.cpp                 | 3 ---
 lld/test/ELF/aarch64-feature-gcs.s | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index ed36994afe2a8..0896bc38fc65a 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -576,9 +576,6 @@ static GcsPolicy getZGcs(opt::InputArgList &args) {
         ret = GcsPolicy::Never;
       else if (kv.second == "always")
         ret = GcsPolicy::Always;
-      else if (StringRef(arg->getValue()) == "gcs")
-        // -z gcs is the same as -z gcs=always
-        ret = GcsPolicy::Always;
       else
         error("unknown -z gcs= value: " + kv.second);
     }
diff --git a/lld/test/ELF/aarch64-feature-gcs.s b/lld/test/ELF/aarch64-feature-gcs.s
index de6045e38fe25..5cd23e159e290 100644
--- a/lld/test/ELF/aarch64-feature-gcs.s
+++ b/lld/test/ELF/aarch64-feature-gcs.s
@@ -12,7 +12,7 @@
 # RUN: llvm-readelf -n gcs | FileCheck --check-prefix GCS %s
 # RUN: ld.lld func1-gcs.o func3-gcs.o --shared -o gcs.so
 # RUN: llvm-readelf -n gcs.so | FileCheck --check-prefix GCS %s
-# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o force-gcs -z gcs
+# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o force-gcs -z gcs=always
 # RUN: llvm-readelf -n force-gcs | FileCheck --allow-empty --check-prefix GCS %s
 # RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs.so -z gcs=always
 # RUN: llvm-readelf -n force-gcs.so | FileCheck --allow-empty --check-prefix GCS %s



More information about the llvm-commits mailing list