Message ID | 001901d13f80$813a7230$83af5690$@foss.arm.com |
---|---|
State | New |
Headers | show |
On 26/12/15 01:55, Thomas Preud'homme wrote: > [Sending on behalf of Andre Vieira] > > Hello, > > This patch adds support for the ARMv8-M Security Extensions 'cmse_nonsecure_call' attribute. This attribute may only be used for function types and when used in combination with the '-mcmse' compilation flag. See Section 5.5 of ARM®v8-M Security Extensions (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html). > > We currently do not support cmse_nonsecure_call functions that pass arguments or return variables on the stack and we diagnose this. > > *** gcc/ChangeLog *** > 2015-10-27 Andre Vieira <andre.simoesdiasvieira@arm.com> > Thomas Preud'homme <thomas.preudhomme@arm.com> > > * gcc/config/arm/arm.c (gimplify.h): New include. > (arm_handle_cmse_nonsecure_call): New. > (arm_attribute_table): Added cmse_nonsecure_call. > > *** gcc/testsuite/ChangeLog *** > 2015-10-27 Andre Vieira <andre.simoesdiasvieira@arm.com> > Thomas Preud'homme <thomas.preudhomme@arm.com> > > * gcc.target/arm/cmse/cmse-3.c: Add tests. > * gcc.target/arm/cmse/cmse-4.c: Add tests. > > > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c > index 0700478ca38307f35d0cb01f83ea182802ba28fa..4b4eea88cbec8e04d5b92210f0af2440ce6fb6e4 100644 > --- a/gcc/config/arm/arm.c > +++ b/gcc/config/arm/arm.c > @@ -61,6 +61,7 @@ > #include "builtins.h" > #include "tm-constrs.h" > #include "rtl-iter.h" > +#include "gimplify.h" > > /* This file should be included last. */ > #include "target-def.h" > @@ -136,6 +137,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *); > static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *); > #endif > static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *); > +static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *); > static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT); > static void arm_output_function_prologue (FILE *, HOST_WIDE_INT); > static int arm_comp_type_attributes (const_tree, const_tree); > @@ -347,6 +349,8 @@ static const struct attribute_spec arm_attribute_table[] = > /* ARMv8-M Security Extensions support. */ > { "cmse_nonsecure_entry", 0, 0, true, false, false, > arm_handle_cmse_nonsecure_entry, false }, > + { "cmse_nonsecure_call", 0, 0, true, false, false, > + arm_handle_cmse_nonsecure_call, false }, > { NULL, 0, 0, false, false, false, NULL, false } > }; > > > @@ -6667,6 +6671,76 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name, > return NULL_TREE; > } > > + > +/* Called upon detection of the use of the cmse_nonsecure_call attribute, this > + function will check whether the attribute is allowed here and will add the > + attribute to the function type tree or otherwise issue a diagnose. The > + reason we check this at declaration time is to only allow the use of the > + attribute with declartions of function pointers and not function > + declartions. */ > + > +static tree > +arm_handle_cmse_nonsecure_call (tree *node, tree name, > + tree /* args */, > + int /* flags */, > + bool *no_add_attrs) > +{ > + tree decl = NULL_TREE; > + tree type, fntype, main_variant; > + > + if (!use_cmse) > + { > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > + if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL) > + { > + decl = *node; > + type = TREE_TYPE (decl); > + } > + > + if (!decl > + || (!(TREE_CODE (type) == POINTER_TYPE > + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) > + && TREE_CODE (type) != FUNCTION_TYPE)) > + { > + warning (OPT_Wattributes, "%qE attribute only applies to base type of a " > + "function pointer", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > + /* type is either a function pointer, when the attribute is used on a function > + * pointer, or a function type when used in a typedef. */ > + if (TREE_CODE (type) == FUNCTION_TYPE) > + fntype = type; > + else > + fntype = TREE_TYPE (type); > + > + *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype); > + > + if (*no_add_attrs) > + return NULL_TREE; > + > + /* Prevent tree's being shared among function types with and without > + cmse_nonsecure_call attribute. Do however make sure they keep the same > + main_variant, this is required for correct DIE output. */ > + main_variant = TYPE_MAIN_VARIANT (fntype); > + fntype = build_distinct_type_copy (fntype); > + TYPE_MAIN_VARIANT (fntype) = main_variant; > + if (TREE_CODE (type) == FUNCTION_TYPE) > + TREE_TYPE (decl) = fntype; > + else > + TREE_TYPE (type) = fntype; > + > + /* Construct a type attribute and add it to the function type. */ > + tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE, > + TYPE_ATTRIBUTES (fntype)); > + TYPE_ATTRIBUTES (fntype) = attrs; > + return NULL_TREE; > +} > + > /* Return 0 if the attributes for two types are incompatible, 1 if they > are compatible, and 2 if they are nearly compatible (which causes a > warning to be generated). */ > diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c > index f806951e90256e8286d2d0f9467b51a73a522e2b..0fe6eff45d2884736ba7049ce4ed5b9785b1018d 100644 > --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c > +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c > @@ -36,3 +36,11 @@ norf (struct span2 a) {} > > void __attribute__ ((cmse_nonsecure_entry)) > foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */ > + > +typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */ > + > +typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */ > + > +typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */ > + > +typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */ > diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c > index ee4121f2e3f49aed4cae7bcc0e70217cbf1bd809..3521dc61f8fb974b43f504e3f634baf27a559b0b 100644 > --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c > +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c > @@ -20,9 +20,16 @@ baz (void) > return qux (); > } > > +void __attribute__ ((cmse_nonsecure_call)) > +quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */ > + > +int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */ > + > /* { dg-final { scan-assembler-times "bxns" 2 } } */ > /* { dg-final { scan-assembler "foo:" } } */ > /* { dg-final { scan-assembler "__acle_se_foo:" } } */ > /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */ > /* { dg-final { scan-assembler "baz:" } } */ > /* { dg-final { scan-assembler "__acle_se_baz:" } } */ > +/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */ > +/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */ > > We welcome any comment. > > Cheers, > > Andre > Ping.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 0700478ca38307f35d0cb01f83ea182802ba28fa..4b4eea88cbec8e04d5b92210f0af2440ce6fb6e4 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -61,6 +61,7 @@ #include "builtins.h" #include "tm-constrs.h" #include "rtl-iter.h" +#include "gimplify.h" /* This file should be included last. */ #include "target-def.h" @@ -136,6 +137,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *); static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *); #endif static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *); +static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *); static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT); static void arm_output_function_prologue (FILE *, HOST_WIDE_INT); static int arm_comp_type_attributes (const_tree, const_tree); @@ -347,6 +349,8 @@ static const struct attribute_spec arm_attribute_table[] = /* ARMv8-M Security Extensions support. */ { "cmse_nonsecure_entry", 0, 0, true, false, false, arm_handle_cmse_nonsecure_entry, false }, + { "cmse_nonsecure_call", 0, 0, true, false, false, + arm_handle_cmse_nonsecure_call, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -6667,6 +6671,76 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name, return NULL_TREE; } + +/* Called upon detection of the use of the cmse_nonsecure_call attribute, this + function will check whether the attribute is allowed here and will add the + attribute to the function type tree or otherwise issue a diagnose. The + reason we check this at declaration time is to only allow the use of the + attribute with declartions of function pointers and not function + declartions. */ + +static tree +arm_handle_cmse_nonsecure_call (tree *node, tree name, + tree /* args */, + int /* flags */, + bool *no_add_attrs) +{ + tree decl = NULL_TREE; + tree type, fntype, main_variant; + + if (!use_cmse) + { + *no_add_attrs = true; + return NULL_TREE; + } + + if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL) + { + decl = *node; + type = TREE_TYPE (decl); + } + + if (!decl + || (!(TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + && TREE_CODE (type) != FUNCTION_TYPE)) + { + warning (OPT_Wattributes, "%qE attribute only applies to base type of a " + "function pointer", name); + *no_add_attrs = true; + return NULL_TREE; + } + + /* type is either a function pointer, when the attribute is used on a function + * pointer, or a function type when used in a typedef. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + fntype = type; + else + fntype = TREE_TYPE (type); + + *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype); + + if (*no_add_attrs) + return NULL_TREE; + + /* Prevent tree's being shared among function types with and without + cmse_nonsecure_call attribute. Do however make sure they keep the same + main_variant, this is required for correct DIE output. */ + main_variant = TYPE_MAIN_VARIANT (fntype); + fntype = build_distinct_type_copy (fntype); + TYPE_MAIN_VARIANT (fntype) = main_variant; + if (TREE_CODE (type) == FUNCTION_TYPE) + TREE_TYPE (decl) = fntype; + else + TREE_TYPE (type) = fntype; + + /* Construct a type attribute and add it to the function type. */ + tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE, + TYPE_ATTRIBUTES (fntype)); + TYPE_ATTRIBUTES (fntype) = attrs; + return NULL_TREE; +} + /* Return 0 if the attributes for two types are incompatible, 1 if they are compatible, and 2 if they are nearly compatible (which causes a warning to be generated). */ diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c index f806951e90256e8286d2d0f9467b51a73a522e2b..0fe6eff45d2884736ba7049ce4ed5b9785b1018d 100644 --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c @@ -36,3 +36,11 @@ norf (struct span2 a) {} void __attribute__ ((cmse_nonsecure_entry)) foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */ + +typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */ + +typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */ + +typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */ + +typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */ diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c index ee4121f2e3f49aed4cae7bcc0e70217cbf1bd809..3521dc61f8fb974b43f504e3f634baf27a559b0b 100644 --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c @@ -20,9 +20,16 @@ baz (void) return qux (); } +void __attribute__ ((cmse_nonsecure_call)) +quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */ + +int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */ + /* { dg-final { scan-assembler-times "bxns" 2 } } */ /* { dg-final { scan-assembler "foo:" } } */ /* { dg-final { scan-assembler "__acle_se_foo:" } } */ /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */ /* { dg-final { scan-assembler "baz:" } } */ /* { dg-final { scan-assembler "__acle_se_baz:" } } */ +/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */ +/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */