[2/7,Arm] Add option -mbranch-protection.

Message ID AM5PR0801MB1844227EE14DD5FAFB2F9352EAB29@AM5PR0801MB1844.eurprd08.prod.outlook.com
State Superseded
Headers
Series [1/7,Arm] Add Armv8.1-M Mainline target feature +pacbti. |

Commit Message

Tejas Belagod Oct. 8, 2021, 12:17 p.m. UTC
  Hi,

Add -mbranch-protection option and its associated parsing routines.
This option enables the code-generation of pointer signing and
authentication instructions in function prologues and epilogues.

Tested on arm-none-eabi. OK for trunk?

2021-10-04  Tejas Belagod  <tbelagod@arm.com>

gcc/ChangeLog:

	* common/config/arm/arm-common.c
	 (arm_print_hit_for_pacbti_option): New.
	 (arm_progress_next_token): New.
	 (arm_parse_pac_ret_clause): New routine for parsing the
	pac-ret clause for -mbranch-protection.
	(arm_parse_pacbti_option): New routine to parse all the options
	to -mbranch-protection.
	* config/arm/arm-protos.h (arm_parse_pacbti_option): Export.
	* config/arm/arm.c (arm_configure)build_target): Handle option
	to -mbranch-protection.
	* config/arm/arm.opt (mbranch-protection). New.
	(arm_enable_pacbti): New.
  

Comments

Richard Earnshaw (lists) Oct. 11, 2021, 12:57 p.m. UTC | #1
On 08/10/2021 13:17, Tejas Belagod via Gcc-patches wrote:
> Hi,
> 
> Add -mbranch-protection option and its associated parsing routines.
> This option enables the code-generation of pointer signing and
> authentication instructions in function prologues and epilogues.
> 
> Tested on arm-none-eabi. OK for trunk?
> 
> 2021-10-04  Tejas Belagod  <tbelagod@arm.com>
> 
> gcc/ChangeLog:
> 
> 	* common/config/arm/arm-common.c
> 	 (arm_print_hit_for_pacbti_option): New.
> 	 (arm_progress_next_token): New.
> 	 (arm_parse_pac_ret_clause): New routine for parsing the
> 	pac-ret clause for -mbranch-protection.
> 	(arm_parse_pacbti_option): New routine to parse all the options
> 	to -mbranch-protection.
> 	* config/arm/arm-protos.h (arm_parse_pacbti_option): Export.
> 	* config/arm/arm.c (arm_configure)build_target): Handle option
> 	to -mbranch-protection.
> 	* config/arm/arm.opt (mbranch-protection). New.
> 	(arm_enable_pacbti): New.
> 

You're missing documentation for invoke.texi.

Also, how does this differ from the exising option in aarch64?  Can the 
code from that be adapted to be made common to both targets rather than 
doing a new implementation?

Finally, there are far to many manifest constants in this patch, they 
need replacing with enums or #defines as appropriate if we cannot share 
the aarch64 code.

R.
  

Patch

diff --git a/gcc/common/config/arm/arm-common.c b/gcc/common/config/arm/arm-common.c
index de898a74165db4d7250aa0097dfab682beb0f99c..188feebb15b52f389d5d0b3ec322be3017efd5a0 100644
--- a/gcc/common/config/arm/arm-common.c
+++ b/gcc/common/config/arm/arm-common.c
@@ -475,6 +475,156 @@  arm_parse_arch_option_name (const arch_option *list, const char *optname,
   return NULL;
 }
 
+static void
+arm_print_hint_for_pacbti_option ()
+{
+  const char *s = "pac-ret[+leaf][+b-key][+bti]"
+		  " | bti[+pac-ret[+leaf][+b-key]]";
+  inform (input_location, "valid arguments are: %s", s);
+}
+
+/* Progress *E to end of next token delimited by DELIMITER.
+   Cache old *E in *OE.  */
+static void
+arm_progress_next_token (const char **oe, const char **e,
+			 size_t *l, const char delimiter)
+{
+  *oe = *e + 1;
+  *e = strchr (*oe, delimiter);
+  *l = *e ? *e - *oe : strlen (*oe);
+}
+
+/* Parse options to -mbranch-protection.  */
+static const char*
+arm_parse_pac_ret_clause (const char *pacret, const char *optname,
+			  unsigned int *pacbti)
+{
+  const char *old_end = NULL;
+  const char *end = strchr (pacret, '+');
+  size_t len = end ? end - pacret : strlen (pacret);
+  if (len == 7 && strncmp (pacret, "pac-ret", len) == 0)
+    {
+      *pacbti |= 2;
+      if (end != NULL)
+	{
+	  /* pac-ret+...  */
+	  arm_progress_next_token (&old_end, &end, &len, '+');
+	  if (len == 4 && strncmp (old_end, "leaf", len) == 0)
+	    {
+	      *pacbti |= 8;
+	      if (end != NULL)
+		{
+		  /* pac-ret+leaf+...  */
+		  arm_progress_next_token (&old_end, &end, &len, '+');
+		  if (len == 5 && strncmp (old_end, "b-key", len) == 0)
+		    {
+		      /* Clear bit for A-key.  */
+		      *pacbti &= 0xfffffffd;
+		      *pacbti |= 4;
+		      /* A non-NULL end indicates its pointing to a '+'.
+			 Advance it to point to the next option in the string.  */
+		      if (end != NULL)
+			end++;
+		    }
+		  else
+		    /* This could be 'bti', leave it to caller to parse.  */
+		    end = old_end;
+		}
+	    }
+	  else if (len == 5 && strncmp (old_end, "b-key", len) == 0)
+	    {
+	      /* Clear bit for A-key.  */
+	      *pacbti &= 0xfffffffd;
+	      *pacbti |= 4;
+	      if (end != NULL)
+		{
+		  /* pac-ret+b-key+...  */
+		  arm_progress_next_token (&old_end, &end, &len, '+');
+		  if (len == 4 && strncmp (old_end, "leaf", len) == 0)
+		    {
+		      *pacbti |= 8;
+		      /* A non-NULL end indicates its pointing to a '+'.
+			 Advance it to point to the next option in the string.  */
+		      if (end != NULL)
+			end++;
+		    }
+		  else
+		    /* This could be 'bti', leave it to caller to parse.  */
+		    end = old_end;
+		}
+	    }
+	  else
+	    {
+	      /* This could be a 'bti' option, so leave it to the caller to
+		 parse.  Fall through to the return.  */
+	      end = old_end;
+	    }
+	}
+    }
+  else
+    {
+      error_at (input_location, "unrecognized %s argument: %s", optname, pacret);
+      arm_print_hint_for_pacbti_option ();
+      return NULL;
+    }
+
+  return end;
+}
+
+unsigned int
+arm_parse_pacbti_option (const char *pacbti, const char *optname, bool complain)
+{
+  unsigned int enable_pacbti = 0;
+  const char *end = strchr (pacbti, '+');
+  size_t len = end ? end - pacbti : strlen (pacbti);
+
+  if (strcmp (pacbti, "none") == 0)
+    return 0;
+
+  if (strcmp (pacbti, "standard") == 0)
+    return 0x3;
+
+  if (len == 3 && strncmp (pacbti, "bti", len) == 0)
+    {
+      /* bti+...  */
+      enable_pacbti |= 1;
+
+      if (end != NULL
+	  && arm_parse_pac_ret_clause (end + 1, optname, &enable_pacbti) != NULL
+	  && complain == true)
+	{
+	/* If the value returned in non-NULL, there's garbage at the end,
+	   so error.  */
+	  error_at (input_location, "unrecognized %s argument: %s",
+		    optname, pacbti);
+	  arm_print_hint_for_pacbti_option ();
+	}
+    }
+  else
+    {
+      /* <pac-ret-clause>+...  */
+      end = arm_parse_pac_ret_clause (pacbti, optname, &enable_pacbti);
+      if (end != NULL)
+	{
+	  if (strcmp (end, "bti") != 0)
+	    {
+	      if (complain == true)
+		{
+		  error_at (input_location, "unrecognized %s argument: %s",
+			    optname, pacbti);
+		  arm_print_hint_for_pacbti_option ();
+		}
+	    }
+	  else
+	    {
+	      enable_pacbti |= 1;
+	    }
+	}
+    }
+
+  return enable_pacbti;
+}
+
 /* List the permitted architecture option names.  If TARGET is a near
    miss for an entry, print out the suggested alternative.  */
 static void
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 9b1f61394ad7d778a6c0b84bc6c805f14709f598..1f6984199382848e6d105ba7afd571a49d1ee885 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -584,6 +584,10 @@  const arch_option *arm_parse_arch_option_name (const arch_option *,
 void arm_parse_option_features (sbitmap, const cpu_arch_option *,
 				const char *);
 
+
+unsigned int arm_parse_pacbti_option (const char *pacbti, const char *optname,
+				      bool complain = true);
+
 void arm_initialize_isa (sbitmap, const enum isa_feature *);
 
 const char * arm_gen_far_branch (rtx *, int, const char * , const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 6c6e77fab666f4aeff023b1f949e3ca0a3545658..1f939a6b79a90430abf120e0aa075dfc1fab29a8 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3217,6 +3217,13 @@  arm_configure_build_target (struct arm_build_target *target,
       tune_opts = strchr (opts->x_arm_tune_string, '+');
     }
 
+  if (opts->x_arm_branch_protection_string)
+    {
+      arm_enable_pacbti
+	= arm_parse_pacbti_option (opts->x_arm_branch_protection_string,
+				   "-mbranch-protection");
+    }
+
   if (arm_selected_arch)
     {
       arm_initialize_isa (target->isa, arm_selected_arch->common.isa_bits);
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index a7677eeb45c805d6a314f4d1d2d6063d8c0b687c..82dd665d327d514d9ad842905ddd3f9bb61e99a4 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -304,6 +304,13 @@  mbranch-cost=
 Target RejectNegative Joined UInteger Var(arm_branch_cost) Init(-1)
 Cost to assume for a branch insn.
 
+mbranch-protection=
+Target RejectNegative Joined Var(arm_branch_protection_string) Save
+Use branch-protection features.
+
+TargetVariable
+unsigned int arm_enable_pacbti = 0x0
+
 mgeneral-regs-only
 Target RejectNegative Mask(GENERAL_REGS_ONLY) Save
 Generate code which uses the core registers only (r0-r14).