diff mbox

[RFC,ARM,4/8] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return

Message ID 001501d13f80$19939080$4cbab180$@foss.arm.com
State New
Headers show

Commit Message

Thomas Preudhomme Dec. 26, 2015, 1:52 a.m. UTC
[Sending on behalf of Andre Vieira]

Hello,

This patch extends support for the ARMv8-M Security Extensions 'cmse_nonsecure_entry' attribute in two ways:

1) Generate two labels for the function, the regular function name and one with the function's name appended to '__acle_se_', this will trigger the linker to create a secure gateway veneer for this entry function.
2) Return from cmse_nonsecure_entry marked functions using bxns.

See Section 5.4 of ARM®v8-M Security Extensions (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).


*** gcc/ChangeLog ***
2015-10-27  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc/config/arm/arm.c (use_return_insn): Change to return with  bxns
          when cmse_nonsecure_entry.
          (output_return_instruction): Likewise.
          (arm_output_function_prologue): Likewise.
          (thumb_pop): Likewise.
          (thumb_exit): Likewise.
          (arm_function_ok_for_sibcall): Disable sibcall for entry functions.
          (arm_asm_declare_function_name): New.
          (thumb1_cmse_nonsecure_entry_return): New.
        * gcc/config/arm/arm-protos.h (arm_asm_declare_function_name): New.
        * gcc/config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
          use arm_asm_declare_function_name.

*** gcc/testsuite/ChangeLog ***
2015-10-27  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-2.c: New.
        * gcc.target/arm/cmse/cmse-4.c: New.




We welcome any comment.

Cheers,

Andre

Comments

Andre Vieira (lists) Jan. 29, 2016, 5:07 p.m. UTC | #1
On 26/12/15 01:52, Thomas Preud'homme wrote:
> [Sending on behalf of Andre Vieira]
>
> Hello,
>
> This patch extends support for the ARMv8-M Security Extensions 'cmse_nonsecure_entry' attribute in two ways:
>
> 1) Generate two labels for the function, the regular function name and one with the function's name appended to '__acle_se_', this will trigger the linker to create a secure gateway veneer for this entry function.
> 2) Return from cmse_nonsecure_entry marked functions using bxns.
>
> See Section 5.4 of ARM®v8-M Security Extensions (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>
>
> *** gcc/ChangeLog ***
> 2015-10-27  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * gcc/config/arm/arm.c (use_return_insn): Change to return with  bxns
>            when cmse_nonsecure_entry.
>            (output_return_instruction): Likewise.
>            (arm_output_function_prologue): Likewise.
>            (thumb_pop): Likewise.
>            (thumb_exit): Likewise.
>            (arm_function_ok_for_sibcall): Disable sibcall for entry functions.
>            (arm_asm_declare_function_name): New.
>            (thumb1_cmse_nonsecure_entry_return): New.
>          * gcc/config/arm/arm-protos.h (arm_asm_declare_function_name): New.
>          * gcc/config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
>            use arm_asm_declare_function_name.
>
> *** gcc/testsuite/ChangeLog ***
> 2015-10-27  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * gcc.target/arm/cmse/cmse-2.c: New.
>          * gcc.target/arm/cmse/cmse-4.c: New.
>
>
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index 85dca057d63544c672188db39b05a33b1be10915..9ee8c333046d9a5beeeeb0487f7b710a5aff42d2 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -31,6 +31,7 @@ extern int arm_volatile_func (void);
>   extern void arm_expand_prologue (void);
>   extern void arm_expand_epilogue (bool);
>   extern void arm_declare_function_name (FILE *, const char *, tree);
> +extern void arm_asm_declare_function_name (FILE *, const char *, tree);
>   extern void thumb2_expand_return (bool);
>   extern const char *arm_strip_name_encoding (const char *);
>   extern void arm_asm_output_labelref (FILE *, const char *);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 5b9e51b10e91eee64e3383c1ed50269c3e6cf24c..e530b772e3cc053c16421a2a2861d815d53ebb01 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -3795,6 +3795,11 @@ use_return_insn (int iscond, rtx sibling)
>   	return 0;
>       }
>
> +  /* ARMv8-M nonsecure entry function need to use bxns to return and thus need
> +     several instructions if anything needs to be popped.  */
> +  if (saved_int_regs && IS_CMSE_ENTRY (func_type))
> +    return 0;
> +
>     /* If there are saved registers but the LR isn't saved, then we need
>        two instructions for the return.  */
>     if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
> @@ -6820,6 +6825,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
>     if (IS_INTERRUPT (func_type))
>       return false;
>
> +  /* ARMv8-M non-secure entry functions need to return with bxns which is only
> +     generated for entry functions themselves.  */
> +  if (IS_CMSE_ENTRY (arm_current_func_type ()))
> +    return false;
> +
>     if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
>       {
>         /* Check that the return value locations are the same.  For
> @@ -19607,6 +19617,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
>   	 (e.g. interworking) then we can load the return address
>   	 directly into the PC.  Otherwise we must load it into LR.  */
>         if (really_return
> +	  && !IS_CMSE_ENTRY (func_type)
>   	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
>   	return_reg = reg_names[PC_REGNUM];
>         else
> @@ -19742,8 +19753,12 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
>   	  break;
>
>   	default:
> +	  if (IS_CMSE_ENTRY (func_type))
> +	    {
> +	      snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
> +	    }
>   	  /* Use bx if it's available.  */
> -	  if (arm_arch5 || arm_arch4t)
> +	  else if (arm_arch5 || arm_arch4t)
>   	    sprintf (instr, "bx%s\t%%|lr", conditional);
>   	  else
>   	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
> @@ -19756,6 +19771,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
>     return "";
>   }
>
> +/* Output in FILE asm statements needed to declare the NAME of the function
> +   defined by its DECL node.  */
> +
> +void
> +arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
> +{
> +  size_t cmse_name_len;
> +  char *cmse_name = 0;
> +  char cmse_prefix[] = "__acle_se_";
> +
> +  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
> +				    DECL_ATTRIBUTES (decl)))
> +    {
> +      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
> +      cmse_name = XALLOCAVEC (char, cmse_name_len);
> +      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
> +      targetm.asm_out.globalize_label (file, cmse_name);
> +    }
> +
> +  if (cmse_name)
> +    {
> +      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
> +      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
> +    }
> +
> +  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
> +  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
> +  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
> +  ASM_OUTPUT_LABEL (file, name);
> +
> +  if (cmse_name)
> +    ASM_OUTPUT_LABEL (file, cmse_name);
> +
> +  ARM_OUTPUT_FN_UNWIND (file, TRUE);
> +}
> +
>   /* Write the function name into the code section, directly preceding
>      the function prologue.
>
> @@ -19805,10 +19856,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
>   {
>     unsigned long func_type;
>
> -  /* ??? Do we want to print some of the below anyway?  */
> -  if (TARGET_THUMB1)
> -    return;
> -
>     /* Sanity check.  */
>     gcc_assert (!arm_ccfsm_state && !arm_target_insn);
>
> @@ -19843,6 +19890,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
>       asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
>     if (IS_STACKALIGN (func_type))
>       asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
> +  if (IS_CMSE_ENTRY (func_type))
> +    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
>
>     asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
>   	       crtl->args.size,
> @@ -23921,8 +23970,8 @@ thumb_pop (FILE *f, unsigned long mask)
>     if (mask & (1 << PC_REGNUM))
>       {
>         /* Catch popping the PC.  */
> -      if (TARGET_INTERWORK || TARGET_BACKTRACE
> -	  || crtl->calls_eh_return)
> +      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
> +	  || IS_CMSE_ENTRY (arm_current_func_type ()))
>   	{
>   	  /* The PC is never poped directly, instead
>   	     it is popped into r3 and then BX is used.  */
> @@ -23944,6 +23993,16 @@ thumb_pop (FILE *f, unsigned long mask)
>     fprintf (f, "}\n");
>   }
>
> +/* Prints assembly to generate a return from a nonsecure entry function for
> +   thumb1.  The thumb2 variant is handled within output_return_instruction.  */
> +
> +static void
> +thumb1_cmse_nonsecure_entry_return (FILE *f, int reg_containing_return_addr)
> +{
> +  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
> +}
> +
> +
>   /* Generate code to return from a thumb function.
>      If 'reg_containing_return_addr' is -1, then the return address is
>      actually on the stack, at the stack pointer.  */
> @@ -23958,6 +24017,9 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
>     machine_mode mode;
>     int size;
>     int restore_a4 = FALSE;
> +  unsigned long func_type;
> +
> +  func_type = arm_current_func_type ();
>
>     /* Compute the registers we need to pop.  */
>     regs_to_pop = 0;
> @@ -23983,7 +24045,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
>         if (crtl->calls_eh_return)
>   	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
>
> -      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
> +      if (IS_CMSE_ENTRY (func_type))
> +	thumb1_cmse_nonsecure_entry_return (f, reg_containing_return_addr);
> +      else
> +	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
>         return;
>       }
>     /* Otherwise if we are not supporting interworking and we have not created
> @@ -23992,7 +24057,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
>     else if (!TARGET_INTERWORK
>   	   && !TARGET_BACKTRACE
>   	   && !is_called_in_ARM_mode (current_function_decl)
> -	   && !crtl->calls_eh_return)
> +	   && !crtl->calls_eh_return
> +	   && !IS_CMSE_ENTRY (func_type))
>       {
>         asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
>         return;
> @@ -24215,7 +24281,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
>       asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
>
>     /* Return to caller.  */
> -  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
> +  if (IS_CMSE_ENTRY (func_type))
> +    thumb1_cmse_nonsecure_entry_return (f, reg_containing_return_addr);
> +  else
> +    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
>   }
>
>
>   /* Scan INSN just before assembler is output for it.
> @@ -25092,6 +25161,12 @@ thumb2_expand_return (bool simple_return)
>
>     if (!simple_return && saved_regs_mask)
>       {
> +      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
> +	 functions or adapt code to handle according to ACLE.  This path should
> +	 not be reachable for cmse_nonsecure_entry functions though we prefer
> +	 to guard it for now to ensure that future code changes do not silently
> +	 change this behavior.  */
> +      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
>         if (num_regs == 1)
>           {
>             rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
> @@ -25509,6 +25584,7 @@ arm_expand_epilogue (bool really_return)
>
>         if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
>             && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
> +	  && !IS_CMSE_ENTRY (func_type)
>             && !IS_STACKALIGN (func_type)
>             && really_return
>             && crtl->args.pretend_args_size == 0
> diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
> index 579a580761ef3019442aedcbb42a748fbd741380..3ca840e2e4fbab03336512ee6fe4fec8eb29917c 100644
> --- a/gcc/config/arm/elf.h
> +++ b/gcc/config/arm/elf.h
> @@ -75,16 +75,7 @@
>
>   /* We might need a ARM specific header to function declarations.  */
>   #undef  ASM_DECLARE_FUNCTION_NAME
> -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
> -  do								\
> -    {								\
> -      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
> -      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
> -      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
> -      ASM_OUTPUT_LABEL(FILE, NAME);				\
> -      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
> -    }								\
> -  while (0)
> +#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
>
>   /* We might need an ARM specific trailer for function declarations.  */
>   #undef  ASM_DECLARE_FUNCTION_SIZE
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..978e65c2261852bfa49aa64e0210600a82ea4ca3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target arm_cmse_ok } */
> +/* { dg-options "-mcmse" }  */
> +
> +void
> +foo (void) {}
> +
> +/* { dg-final { scan-assembler-not "bxns" } } */
> +/* { dg-final { scan-assembler "foo:" } } */
> +/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..ee4121f2e3f49aed4cae7bcc0e70217cbf1bd809
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target arm_cmse_ok } */
> +/* { dg-options "-mcmse" }  */
> +
> +struct span {
> +  int a, b;
> +};
> +
> +extern int qux (void);
> +
> +void __attribute__ ((cmse_nonsecure_entry))
> +foo (void) {}
> +
> +static void __attribute__ ((cmse_nonsecure_entry))
> +bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
> +
> +int __attribute__ ((cmse_nonsecure_entry))
> +baz (void)
> +{
> +  return qux ();
> +}
> +
> +/* { 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:" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..2846ce6cc203f1810977656bdc09ff86419b7007
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target arm_cmse_ok } */
> +/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
> +
> +
> +int __attribute__ ((cmse_nonsecure_entry))
> +foo (int a)
> +{
> +  return a + 1;
> +}
> +
> +/* { dg-final { scan-assembler "foo:" } } */
> +/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
>
>
> We welcome any comment.
>
> Cheers,
>
> Andre
>
Ping.
diff mbox

Patch

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 85dca057d63544c672188db39b05a33b1be10915..9ee8c333046d9a5beeeeb0487f7b710a5aff42d2 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -31,6 +31,7 @@  extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
 extern void arm_declare_function_name (FILE *, const char *, tree);
+extern void arm_asm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 5b9e51b10e91eee64e3383c1ed50269c3e6cf24c..e530b772e3cc053c16421a2a2861d815d53ebb01 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3795,6 +3795,11 @@  use_return_insn (int iscond, rtx sibling)
 	return 0;
     }
 
+  /* ARMv8-M nonsecure entry function need to use bxns to return and thus need
+     several instructions if anything needs to be popped.  */
+  if (saved_int_regs && IS_CMSE_ENTRY (func_type))
+    return 0;
+
   /* If there are saved registers but the LR isn't saved, then we need
      two instructions for the return.  */
   if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
@@ -6820,6 +6825,11 @@  arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_INTERRUPT (func_type))
     return false;
 
+  /* ARMv8-M non-secure entry functions need to return with bxns which is only
+     generated for entry functions themselves.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    return false;
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -19607,6 +19617,7 @@  output_return_instruction (rtx operand, bool really_return, bool reverse,
 	 (e.g. interworking) then we can load the return address
 	 directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
+	  && !IS_CMSE_ENTRY (func_type)
 	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
 	return_reg = reg_names[PC_REGNUM];
       else
@@ -19742,8 +19753,12 @@  output_return_instruction (rtx operand, bool really_return, bool reverse,
 	  break;
 
 	default:
+	  if (IS_CMSE_ENTRY (func_type))
+	    {
+	      snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    }
 	  /* Use bx if it's available.  */
-	  if (arm_arch5 || arm_arch4t)
+	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
 	  else
 	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19756,6 +19771,42 @@  output_return_instruction (rtx operand, bool really_return, bool reverse,
   return "";
 }
 
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+    }
+
+  if (cmse_name)
+    {
+      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
+    }
+
+  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_LABEL (file, name);
+
+  if (cmse_name)
+    ASM_OUTPUT_LABEL (file, cmse_name);
+
+  ARM_OUTPUT_FN_UNWIND (file, TRUE);
+}
+
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -19805,10 +19856,6 @@  arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  /* ??? Do we want to print some of the below anyway?  */
-  if (TARGET_THUMB1)
-    return;
-
   /* Sanity check.  */
   gcc_assert (!arm_ccfsm_state && !arm_target_insn);
 
@@ -19843,6 +19890,8 @@  arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
   if (IS_STACKALIGN (func_type))
     asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
+  if (IS_CMSE_ENTRY (func_type))
+    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
 	       crtl->args.size,
@@ -23921,8 +23970,8 @@  thumb_pop (FILE *f, unsigned long mask)
   if (mask & (1 << PC_REGNUM))
     {
       /* Catch popping the PC.  */
-      if (TARGET_INTERWORK || TARGET_BACKTRACE
-	  || crtl->calls_eh_return)
+      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
+	  || IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
 	  /* The PC is never poped directly, instead
 	     it is popped into r3 and then BX is used.  */
@@ -23944,6 +23993,16 @@  thumb_pop (FILE *f, unsigned long mask)
   fprintf (f, "}\n");
 }
 
+/* Prints assembly to generate a return from a nonsecure entry function for
+   thumb1.  The thumb2 variant is handled within output_return_instruction.  */
+
+static void
+thumb1_cmse_nonsecure_entry_return (FILE *f, int reg_containing_return_addr)
+{
+  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+}
+
+
 /* Generate code to return from a thumb function.
    If 'reg_containing_return_addr' is -1, then the return address is
    actually on the stack, at the stack pointer.  */
@@ -23958,6 +24017,9 @@  thumb_exit (FILE *f, int reg_containing_return_addr)
   machine_mode mode;
   int size;
   int restore_a4 = FALSE;
+  unsigned long func_type;
+
+  func_type = arm_current_func_type ();
 
   /* Compute the registers we need to pop.  */
   regs_to_pop = 0;
@@ -23983,7 +24045,10 @@  thumb_exit (FILE *f, int reg_containing_return_addr)
       if (crtl->calls_eh_return)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
-      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+      if (IS_CMSE_ENTRY (func_type))
+	thumb1_cmse_nonsecure_entry_return (f, reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
     }
   /* Otherwise if we are not supporting interworking and we have not created
@@ -23992,7 +24057,8 @@  thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
 	   && !TARGET_BACKTRACE
 	   && !is_called_in_ARM_mode (current_function_decl)
-	   && !crtl->calls_eh_return)
+	   && !crtl->calls_eh_return
+	   && !IS_CMSE_ENTRY (func_type))
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -24215,7 +24281,10 @@  thumb_exit (FILE *f, int reg_containing_return_addr)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
-  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+  if (IS_CMSE_ENTRY (func_type))
+    thumb1_cmse_nonsecure_entry_return (f, reg_containing_return_addr);
+  else
+    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
 

 /* Scan INSN just before assembler is output for it.
@@ -25092,6 +25161,12 @@  thumb2_expand_return (bool simple_return)
 
   if (!simple_return && saved_regs_mask)
     {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to guard it for now to ensure that future code changes do not silently
+	 change this behavior.  */
+      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
       if (num_regs == 1)
         {
           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
@@ -25509,6 +25584,7 @@  arm_expand_epilogue (bool really_return)
 
       if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
           && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+	  && !IS_CMSE_ENTRY (func_type)
           && !IS_STACKALIGN (func_type)
           && really_return
           && crtl->args.pretend_args_size == 0
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index 579a580761ef3019442aedcbb42a748fbd741380..3ca840e2e4fbab03336512ee6fe4fec8eb29917c 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -75,16 +75,7 @@ 
 
 /* We might need a ARM specific header to function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
-  do								\
-    {								\
-      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
-      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
-      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
-      ASM_OUTPUT_LABEL(FILE, NAME);				\
-      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
-    }								\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
 
 /* We might need an ARM specific trailer for function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_SIZE
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
new file mode 100644
index 0000000000000000000000000000000000000000..978e65c2261852bfa49aa64e0210600a82ea4ca3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-mcmse" }  */
+
+void
+foo (void) {}
+
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee4121f2e3f49aed4cae7bcc0e70217cbf1bd809
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -0,0 +1,28 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+
+extern int qux (void);
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (void) {}
+
+static void __attribute__ ((cmse_nonsecure_entry))
+bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return qux ();
+}
+
+/* { 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:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..2846ce6cc203f1810977656bdc09ff86419b7007
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
+
+
+int __attribute__ ((cmse_nonsecure_entry))
+foo (int a)
+{
+  return a + 1;
+}
+
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */