@@ -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
@@ -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 *);
@@ -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);
@@ -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).