This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/3][GCC][AARCH64] Add new -mbranch-protection option to combine pointer signing and BTI
- From: Sam Tebbs <Sam dot Tebbs at arm dot com>
- To: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Earnshaw <Richard dot Earnshaw at arm dot com>, Marcus Shawcroft <Marcus dot Shawcroft at arm dot com>, James Greenhalgh <James dot Greenhalgh at arm dot com>, nd <nd at arm dot com>
- Date: Fri, 2 Nov 2018 17:31:20 +0000
- Subject: [PATCH 2/3][GCC][AARCH64] Add new -mbranch-protection option to combine pointer signing and BTI
Hi all,
The -mbranch-protection option combines the functionality of
-msign-return-address and the BTI features new in Armv8.5 to better reflect
their relationship. This new option therefore supersedes and deprecates the
existing -msign-return-address option.
-mbranch-protection=[none|standard|<types>] - Turns on different types of branch
protection available where:
* "none": Turn of all types of branch protection
* "standard" : Turns on all the types of protection to their respective
standard levels.
* <types> can be "+" separated protection types:
* "bti" : Branch Target Identification Mechanism.
* "pac-ret{+leaf+b-key}": Return Address Signing. The default return
address signing is enabled by signing functions that save the return
address to memory (non-leaf functions will practically always do this)
using the a-key. The optional tuning arguments allow the user to
extend the scope of return address signing to include leaf functions
and to change the key to b-key. The tuning arguments must proceed the
protection type "pac-ret".
Thus -mbranch-protection=standard -> -mbranch-protection=bti+pac-ret.
Its mapping to -msign-return-address is as follows:
* -mbranch-protection=none -> -msign-return-address=none
* -mbranch-protection=standard -> -msign-return-address=leaf
* -mbranch-protection=pac-ret -> -msign-return-address=non-leaf
* -mbranch-protection=pac-ret+leaf -> -msign-return-address=all
This patch implements the option's skeleton and the "none", "standard" and
"pac-ret" types (along with its "leaf" subtype).
The previous patch in this series is here:
https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00103.html
Bootstrapped successfully and tested on aarch64-none-elf with no regressions.
OK for trunk?
gcc/ChangeLog:
2018-11-02 Sam Tebbs<sam.tebbs@arm.com>
* config/aarch64/aarch64.c (BRANCH_PROTEC_STR_MAX,
aarch64_parse_branch_protection,
struct aarch64_branch_protec_type,
aarch64_handle_no_branch_protection,
aarch64_handle_standard_branch_protection,
aarch64_validate_mbranch_protection,
aarch64_handle_pac_ret_protection,
aarch64_handle_attr_branch_protection,
accepted_branch_protection_string,
aarch64_pac_ret_subtypes,
aarch64_branch_protec_types,
aarch64_handle_pac_ret_leaf): Define.
(aarch64_override_options_after_change_1): Add check for
accepted_branch_protection_string.
(aarch64_override_options): Add check for
accepted_branch_protection_string.
(aarch64_option_save): Save accepted_branch_protection_string.
(aarch64_option_restore): Save
accepted_branch_protection_string.
* config/aarch64/aarch64.c (aarch64_attributes): Add branch-protection.
* config/aarch64/aarch64.opt: Add mbranch-protection. Deprecate
msign-return-address.
* doc/invoke.texi: Add mbranch-protection.
gcc/testsuite/ChangeLog:
2018-11-02 Sam Tebbs<sam.tebbs@arm.com>
* (gcc.target/aarch64/return_address_sign_1.c,
gcc.target/aarch64/return_address_sign_2.c,
gcc.target/aarch64/return_address_sign_3.c (__attribute__)): Change
option to -mbranch-protection.
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b44ee40115dce526c7cc302b2a47c28ab8b41508..121348dbd909f42717efea163ea6b7c545f5b1c7 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -183,6 +183,12 @@ bool aarch64_pcrelative_literal_loads;
/* Global flag for whether frame pointer is enabled. */
bool aarch64_use_frame_pointer;
+#define BRANCH_PROTEC_STR_MAX 255
+char *accepted_branch_protection_string = NULL;
+
+static enum aarch64_parse_opt_result
+aarch64_parse_branch_protection (const char*, char**);
+
/* Support for command line parsing of boolean flags in the tuning
structures. */
struct aarch64_flag_desc
@@ -1108,6 +1114,80 @@ aarch64_cc;
#define AARCH64_INVERSE_CONDITION_CODE(X) ((aarch64_cc) (((int) X) ^ 1))
+struct aarch64_branch_protec_type
+{
+ /* The type's name that the user passes to the branch-protection option
+ string. */
+ const char* name;
+ /* Function to handle the protection type and set global variables.
+ First argument is the string token corresponding with this type and the
+ second argument is the next token in the option string.
+ Return values:
+ * AARCH64_PARSE_OK: Handling was sucessful.
+ * AARCH64_INVALID_ARG: The type is invalid in this context and the caller
+ should print an error.
+ * AARCH64_INVALID_FEATURE: The type is invalid and the handler prints its
+ own error. */
+ enum aarch64_parse_opt_result (*handler)(char*, char*);
+ /* A list of types that can follow this type in the option string. */
+ const aarch64_branch_protec_type* subtypes;
+ unsigned int num_subtypes;
+};
+
+static enum aarch64_parse_opt_result
+aarch64_handle_no_branch_protection (char* str ATTRIBUTE_UNUSED, char* rest)
+{
+ aarch64_ra_sign_scope = AARCH64_FUNCTION_NONE;
+ if (rest)
+ {
+ error ("unexpected %<%s%> after %<%s%>", rest, str);
+ return AARCH64_PARSE_INVALID_FEATURE;
+ }
+ return AARCH64_PARSE_OK;
+}
+
+static enum aarch64_parse_opt_result
+aarch64_handle_standard_branch_protection (char* str ATTRIBUTE_UNUSED,
+ char* rest ATTRIBUTE_UNUSED)
+{
+ aarch64_ra_sign_scope = AARCH64_FUNCTION_NON_LEAF;
+ if (rest)
+ {
+ error ("unexpected %<%s%> after %<%s%>", rest, str);
+ return AARCH64_PARSE_INVALID_FEATURE;
+ }
+ return AARCH64_PARSE_OK;
+}
+
+static enum aarch64_parse_opt_result
+aarch64_handle_pac_ret_protection (char* str ATTRIBUTE_UNUSED,
+ char* rest ATTRIBUTE_UNUSED)
+{
+ aarch64_ra_sign_scope = AARCH64_FUNCTION_NON_LEAF;
+ return AARCH64_PARSE_OK;
+}
+
+static enum aarch64_parse_opt_result
+aarch64_handle_pac_ret_leaf (char* str ATTRIBUTE_UNUSED,
+ char* rest ATTRIBUTE_UNUSED)
+{
+ aarch64_ra_sign_scope = AARCH64_FUNCTION_ALL;
+ return AARCH64_PARSE_OK;
+}
+
+static const struct aarch64_branch_protec_type aarch64_pac_ret_subtypes[] = {
+ { "leaf", aarch64_handle_pac_ret_leaf, NULL, 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const struct aarch64_branch_protec_type aarch64_branch_protec_types[] = {
+ { "none", aarch64_handle_no_branch_protection, NULL, 0 },
+ { "standard", aarch64_handle_standard_branch_protection, NULL, 0 },
+ { "pac-ret", aarch64_handle_pac_ret_protection, aarch64_pac_ret_subtypes,
+ sizeof (aarch64_pac_ret_subtypes) / sizeof (aarch64_branch_protec_type) },
+ { NULL, NULL, NULL, 0 }
+};
+
/* The condition codes of the processor, and the inverse function. */
static const char * const aarch64_condition_codes[] =
{
@@ -10894,6 +10974,12 @@ aarch64_parse_override_string (const char* input_string,
static void
aarch64_override_options_after_change_1 (struct gcc_options *opts)
{
+ if (accepted_branch_protection_string)
+ {
+ opts->x_aarch64_branch_protection_string
+ = xstrdup (accepted_branch_protection_string);
+ }
+
/* PR 70044: We have to be careful about being called multiple times for the
same function. This means all changes should be repeatable. */
@@ -11179,6 +11265,109 @@ aarch64_validate_mcpu (const char *str, const struct processor **res,
return false;
}
+/* Parses CONST_STR for branch protection features specified in
+ aarch64_branch_protec_types, and set any global variables required. Returns
+ the parsing result and assigns LAST_STR to the last processed token from
+ CONST_STR so that it can be used for error reporting. */
+
+static enum
+aarch64_parse_opt_result aarch64_parse_branch_protection (const char *const_str,
+ char** last_str)
+{
+ char *str = xstrdup (const_str);
+ str = strtok (str, "+");
+ enum aarch64_parse_opt_result res = AARCH64_PARSE_OK;
+ if (!str)
+ res = AARCH64_PARSE_MISSING_ARG;
+ else
+ {
+ char *next_str = strtok (NULL, "+");
+ /* Reset the branch protection features to their defaults. */
+ aarch64_handle_no_branch_protection (NULL, NULL);
+
+ while (str && res == AARCH64_PARSE_OK)
+ {
+ const aarch64_branch_protec_type* type = aarch64_branch_protec_types;
+ bool found = false;
+ /* Search for this type. */
+ while (type && type->name && !found && res == AARCH64_PARSE_OK)
+ {
+ if (strcmp (str, type->name) == 0)
+ {
+ found = true;
+ res = type->handler (str, next_str);
+ str = next_str;
+ next_str = strtok (NULL, "+");
+ }
+ else
+ type++;
+ }
+ if (found && res == AARCH64_PARSE_OK)
+ {
+ bool found_subtype = true;
+ /* Loop through each token until we find one that isn't a
+ subtype. */
+ while (found_subtype)
+ {
+ found_subtype = false;
+ const aarch64_branch_protec_type *subtype = type->subtypes;
+ /* Search for the subtype. */
+ while (str && subtype && subtype->name && !found_subtype
+ && res == AARCH64_PARSE_OK)
+ {
+ if (strcmp (str, subtype->name) == 0)
+ {
+ found_subtype = true;
+ res = subtype->handler (str, next_str);
+ str = next_str;
+ next_str = strtok (NULL, "+");
+ }
+ else
+ subtype++;
+ }
+ }
+ }
+ else if (!found)
+ res = AARCH64_PARSE_INVALID_ARG;
+ }
+ }
+ /* Copy the last processed token into the argument to pass it back.
+ Used by option and attribute validation to print the offending token. */
+ if (last_str)
+ {
+ if (str) strcpy (*last_str, str);
+ else *last_str = NULL;
+ }
+ if (res == AARCH64_PARSE_OK)
+ {
+ /* If needed, alloc the accepted string then copy in const_str.
+ Used by override_option_after_change_1. */
+ if (!accepted_branch_protection_string)
+ accepted_branch_protection_string = (char *) xmalloc (
+ BRANCH_PROTEC_STR_MAX
+ + 1);
+ strncpy (accepted_branch_protection_string, const_str,
+ BRANCH_PROTEC_STR_MAX + 1);
+ /* Forcibly null-terminate. */
+ accepted_branch_protection_string[BRANCH_PROTEC_STR_MAX] = '\0';
+ }
+ return res;
+}
+
+static bool
+aarch64_validate_mbranch_protection (const char *const_str)
+{
+ char *str = (char *) xmalloc (strlen (const_str));
+ enum aarch64_parse_opt_result res =
+ aarch64_parse_branch_protection (const_str, &str);
+ if (res == AARCH64_PARSE_INVALID_ARG)
+ error ("invalid arg %<%s%> for %<-mbranch-protection=%>", str);
+ else if (res == AARCH64_PARSE_MISSING_ARG)
+ error ("missing arg for %<-mbranch-protection=%>");
+ free (str);
+ return res == AARCH64_PARSE_OK;
+}
+
/* Validate a command-line -march option. Parse the arch and extensions
(if any) specified in STR and throw errors if appropriate. Put the
results, if they are valid, in RES and ISA_FLAGS. Return whether the
@@ -11313,6 +11502,9 @@ aarch64_override_options (void)
selected_arch = NULL;
selected_tune = NULL;
+ if (aarch64_branch_protection_string)
+ aarch64_validate_mbranch_protection (aarch64_branch_protection_string);
+
/* -mcpu=CPU is shorthand for -march=ARCH_FOR_CPU, -mtune=CPU.
If either of -march or -mtune is given, they override their
respective component of -mcpu. */
@@ -11475,6 +11667,8 @@ static void
aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
{
ptr->x_aarch64_override_tune_string = opts->x_aarch64_override_tune_string;
+ ptr->x_aarch64_branch_protection_string
+ = opts->x_aarch64_branch_protection_string;
}
/* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisions
@@ -11488,6 +11682,13 @@ aarch64_option_restore (struct gcc_options *opts, struct cl_target_option *ptr)
opts->x_explicit_arch = ptr->x_explicit_arch;
selected_arch = aarch64_get_arch (ptr->x_explicit_arch);
opts->x_aarch64_override_tune_string = ptr->x_aarch64_override_tune_string;
+ opts->x_aarch64_branch_protection_string
+ = ptr->x_aarch64_branch_protection_string;
+ if (opts->x_aarch64_branch_protection_string)
+ {
+ aarch64_parse_branch_protection (opts->x_aarch64_branch_protection_string,
+ NULL);
+ }
aarch64_override_options_internal (opts);
}
@@ -11682,6 +11883,34 @@ aarch64_handle_attr_cpu (const char *str)
return false;
}
+/* Handle the argument STR to the branch-protection= attribute. */
+
+ static bool
+ aarch64_handle_attr_branch_protection (const char* str)
+ {
+ char *err_str = (char *) xmalloc (strlen (str));
+ enum aarch64_parse_opt_result res = aarch64_parse_branch_protection (str,
+ &err_str);
+ switch (res)
+ {
+ case AARCH64_PARSE_MISSING_ARG:
+ error ("missing argument to %<target(\"branch-protection=\")%> pragma or\
+ attribute");
+ break;
+ case AARCH64_PARSE_INVALID_ARG:
+ error ("invalid protection type (\"%s\") in %<target(\"branch-protection\
+ =\")%> pragma or attribute", err_str);
+ aarch64_print_hint_for_core (str);
+ break;
+ case AARCH64_PARSE_OK:
+ return true;
+ default:
+ gcc_unreachable ();
+ }
+ free (err_str);
+ return false;
+ }
+
/* Handle the argument STR to the tune= target attribute. */
static bool
@@ -11780,6 +12009,8 @@ static const struct aarch64_attribute_info aarch64_attributes[] =
{ "cpu", aarch64_attr_custom, false, aarch64_handle_attr_cpu, OPT_mcpu_ },
{ "tune", aarch64_attr_custom, false, aarch64_handle_attr_tune,
OPT_mtune_ },
+ { "branch-protection", aarch64_attr_custom, false,
+ aarch64_handle_attr_branch_protection, OPT_mbranch_protection_ },
{ "sign-return-address", aarch64_attr_enum, false, NULL,
OPT_msign_return_address_ },
{ NULL, aarch64_attr_custom, false, NULL, OPT____ }
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index b2e80cbf6f1f9727c4309874b1122f975fb6b9be..9460636d93b67af1525f028176aa78e6fed4e45f 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -149,8 +149,12 @@ mpc-relative-literal-loads
Target Report Save Var(pcrelative_literal_loads) Init(2) Save
PC relative literal loads.
+mbranch-protection=
+Target RejectNegative Joined Var(aarch64_branch_protection_string) Save
+Use branch-protection features.
+
msign-return-address=
-Target RejectNegative Report Joined Enum(aarch64_ra_sign_scope_t) Var(aarch64_ra_sign_scope) Init(AARCH64_FUNCTION_NONE) Save
+Target Deprecated RejectNegative Joined Enum(aarch64_ra_sign_scope_t) Var(aarch64_ra_sign_scope) Init(AARCH64_FUNCTION_NONE) Save
Select return address signing scope.
Enum
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e290128f535f3e6b515bff5a81fae0aa0d1c8baf..07cfe69dc3dd9161a2dd93089ccf52ef251208d2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -622,6 +622,7 @@ Objective-C and Objective-C++ Dialects}.
-mlow-precision-recip-sqrt -mlow-precision-sqrt -mlow-precision-div @gol
-mpc-relative-literal-loads @gol
-msign-return-address=@var{scope} @gol
+-mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] @gol
-march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol
-moverride=@var{string} -mverbose-cost-dump -mtrack-speculation}
@@ -15221,13 +15222,18 @@ accessed using a single instruction and emitted after each function. This
limits the maximum size of functions to 1MB. This is enabled by default for
@option{-mcmodel=tiny}.
-@item -msign-return-address=@var{scope}
-@opindex msign-return-address
-Select the function scope on which return address signing will be applied.
-Permissible values are @samp{none}, which disables return address signing,
-@samp{non-leaf}, which enables pointer signing for functions which are not leaf
-functions, and @samp{all}, which enables pointer signing for all functions. The
-default value is @samp{none}.
+@item -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}]
+@opindex mbranch-protection
+Select the branch protection features to use.
+@samp{none} is the default and turns off all types of branch protection.
+@samp{standard} turns on all types of branch protection features. If a feature
+has additional tuning options, then @samp{standard} sets it to its standard
+level.
+@samp{pac-ret[+@var{leaf}]} turns on return address signing to its standard
+level: signing functions that save the return address to memory (non-leaf
+functions will practically always do this) using the a-key. The optional
+argument @samp{leaf} can be used to extend the signing to include leaf
+functions.
@item -msve-vector-bits=@var{bits}
@opindex msve-vector-bits
@@ -16241,6 +16247,10 @@ Values @samp{arc600}, @samp{arc601}, @samp{arc700} and
@opindex multcost
Replaced by @option{-mmultcost}.
+@item -msign-return-address=@var{scope}
+@opindex msign-return-address
+Replaced by @option{-mbranch-protection}
+
@end table
@node ARM Options
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
index f87c3d28d1edff473a787a39a436e57076f97508..0140bee194f5a3ec53e794984c2f9b0e96bdbb63 100644
--- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
@@ -1,6 +1,6 @@
/* Testing return address signing where no combined instructions used. */
/* { dg-do compile } */
-/* { dg-options "-O2 -msign-return-address=all" } */
+/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf" } */
/* { dg-require-effective-target lp64 } */
int foo (int);
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c
index c5c1439b92e6637f85c47c6161cd797c0d68df25..a4bc5b4533382d3d21085a763028576f72531ed7 100644
--- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c
@@ -1,6 +1,6 @@
/* Testing return address signing where combined instructions used. */
/* { dg-do compile } */
-/* { dg-options "-O2 -msign-return-address=all" } */
+/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf" } */
/* { dg-require-effective-target lp64 } */
int foo (int);
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_3.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_3.c
index 7d9ec6eebd1ce452013d2895a551671c59e98f0c..e39ed34ab1c13d1368f4a625b4a466eb76354ef8 100644
--- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_3.c
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_3.c
@@ -1,17 +1,17 @@
/* Testing the disable of return address signing. */
/* { dg-do compile } */
-/* { dg-options "-O2 -msign-return-address=all" } */
+/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf" } */
/* { dg-require-effective-target lp64 } */
int bar (int, int);
-int __attribute__ ((target ("arch=armv8.3-a, sign-return-address=non-leaf")))
+int __attribute__ ((target ("arch=armv8.3-a, branch-protection=pac-ret")))
func1_leaf (int a, int b, int c, int d)
{
return a + b + c + d;
}
-int __attribute__ ((target ("arch=armv8.3-a, sign-return-address=none")))
+int __attribute__ ((target ("arch=armv8.3-a, branch-protection=none")))
func2_none (int a, int b, int c, int d)
{
return c + bar (a, b) + d;