[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.simoesdiasvie...@arm.com>
Thomas Preud'homme <thomas.preudho...@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.simoesdiasvie...@arm.com>
Thomas Preud'homme <thomas.preudho...@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