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 <[email protected]>
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).