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  <tbela...@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.
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).

Reply via email to