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