Commit 9ad1f699 by Andre Vieira Committed by Andre Vieira

ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns

return

    gcc/ChangeLog:
    2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
	    Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* 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.
	(thumb2_expand_return): Assert that entry functions always have simple
	returns.
	(arm_expand_epilogue): Handle entry functions.
	(arm_function_ok_for_sibcall): Disable sibcall for entry functions.
	(arm_asm_declare_function_name): New.
	* config/arm/arm-protos.h (arm_asm_declare_function_name): New.
	* config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
	use arm_asm_declare_function_name.

    gcc/testsuite/ChangeLog:
    2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		Thomas Preud'homme  <thomas.preudhomme@arm.com>

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


Co-Authored-By: Thomas Preud'homme <thomas.preudhomme@arm.com>

From-SVN: r243189
parent 97b0656d
2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com> 2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com>
Thomas Preud'homme <thomas.preudhomme@arm.com> Thomas Preud'homme <thomas.preudhomme@arm.com>
* 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.
(thumb2_expand_return): Assert that entry functions always have simple
returns.
(arm_expand_epilogue): Handle entry functions.
(arm_function_ok_for_sibcall): Disable sibcall for entry functions.
(arm_asm_declare_function_name): New.
* config/arm/arm-protos.h (arm_asm_declare_function_name): New.
* config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
use arm_asm_declare_function_name.
2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com>
Thomas Preud'homme <thomas.preudhomme@arm.com>
* config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New. * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
(arm_attribute_table): Added cmse_nonsecure_entry (arm_attribute_table): Added cmse_nonsecure_entry
(arm_compute_func_type): Handle cmse_nonsecure_entry. (arm_compute_func_type): Handle cmse_nonsecure_entry.
...@@ -33,6 +33,7 @@ extern int arm_volatile_func (void); ...@@ -33,6 +33,7 @@ extern int arm_volatile_func (void);
extern void arm_expand_prologue (void); extern void arm_expand_prologue (void);
extern void arm_expand_epilogue (bool); extern void arm_expand_epilogue (bool);
extern void arm_declare_function_name (FILE *, const char *, tree); 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 void thumb2_expand_return (bool);
extern const char *arm_strip_name_encoding (const char *); extern const char *arm_strip_name_encoding (const char *);
extern void arm_asm_output_labelref (FILE *, const char *); extern void arm_asm_output_labelref (FILE *, const char *);
......
...@@ -3866,6 +3866,11 @@ use_return_insn (int iscond, rtx sibling) ...@@ -3866,6 +3866,11 @@ use_return_insn (int iscond, rtx sibling)
return 0; 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 /* If there are saved registers but the LR isn't saved, then we need
two instructions for the return. */ two instructions for the return. */
if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM))) if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
...@@ -6906,6 +6911,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp) ...@@ -6906,6 +6911,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
if (IS_INTERRUPT (func_type)) if (IS_INTERRUPT (func_type))
return false; 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)))) if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
{ {
/* Check that the return value locations are the same. For /* Check that the return value locations are the same. For
...@@ -18568,6 +18578,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse, ...@@ -18568,6 +18578,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
(e.g. interworking) then we can load the return address (e.g. interworking) then we can load the return address
directly into the PC. Otherwise we must load it into LR. */ directly into the PC. Otherwise we must load it into LR. */
if (really_return if (really_return
&& !IS_CMSE_ENTRY (func_type)
&& (IS_INTERRUPT (func_type) || !TARGET_INTERWORK)) && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
return_reg = reg_names[PC_REGNUM]; return_reg = reg_names[PC_REGNUM];
else else
...@@ -18708,8 +18719,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse, ...@@ -18708,8 +18719,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
break; break;
default: default:
if (IS_CMSE_ENTRY (func_type))
snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
/* Use bx if it's available. */ /* Use bx if it's available. */
if (arm_arch5 || arm_arch4t) else if (arm_arch5 || arm_arch4t)
sprintf (instr, "bx%s\t%%|lr", conditional); sprintf (instr, "bx%s\t%%|lr", conditional);
else else
sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional); sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
...@@ -18722,6 +18735,44 @@ output_return_instruction (rtx operand, bool really_return, bool reverse, ...@@ -18722,6 +18735,44 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
return ""; 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_";
/* When compiling with ARMv8-M Security Extensions enabled, we should print an
extra function label for each function with the 'cmse_nonsecure_entry'
attribute. This extra function label should be prepended with
'__acle_se_', telling the linker that it needs to create secure gateway
veneers for this function. */
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);
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 /* Write the function name into the code section, directly preceding
the function prologue. the function prologue.
...@@ -18771,10 +18822,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size) ...@@ -18771,10 +18822,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
{ {
unsigned long func_type; unsigned long func_type;
/* ??? Do we want to print some of the below anyway? */
if (TARGET_THUMB1)
return;
/* Sanity check. */ /* Sanity check. */
gcc_assert (!arm_ccfsm_state && !arm_target_insn); gcc_assert (!arm_ccfsm_state && !arm_target_insn);
...@@ -18809,6 +18856,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size) ...@@ -18809,6 +18856,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n"); asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
if (IS_STACKALIGN (func_type)) if (IS_STACKALIGN (func_type))
asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n"); 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", asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
crtl->args.size, crtl->args.size,
...@@ -22915,8 +22964,8 @@ thumb_pop (FILE *f, unsigned long mask) ...@@ -22915,8 +22964,8 @@ thumb_pop (FILE *f, unsigned long mask)
if (mask & (1 << PC_REGNUM)) if (mask & (1 << PC_REGNUM))
{ {
/* Catch popping the PC. */ /* Catch popping the PC. */
if (TARGET_INTERWORK || TARGET_BACKTRACE if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
|| crtl->calls_eh_return) || IS_CMSE_ENTRY (arm_current_func_type ()))
{ {
/* The PC is never poped directly, instead /* The PC is never poped directly, instead
it is popped into r3 and then BX is used. */ it is popped into r3 and then BX is used. */
...@@ -22977,7 +23026,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr) ...@@ -22977,7 +23026,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
if (crtl->calls_eh_return) if (crtl->calls_eh_return)
asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM); 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 (arm_current_func_type ()))
asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
else
asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
return; return;
} }
/* Otherwise if we are not supporting interworking and we have not created /* Otherwise if we are not supporting interworking and we have not created
...@@ -22986,7 +23038,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr) ...@@ -22986,7 +23038,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
else if (!TARGET_INTERWORK else if (!TARGET_INTERWORK
&& !TARGET_BACKTRACE && !TARGET_BACKTRACE
&& !is_called_in_ARM_mode (current_function_decl) && !is_called_in_ARM_mode (current_function_decl)
&& !crtl->calls_eh_return) && !crtl->calls_eh_return
&& !IS_CMSE_ENTRY (arm_current_func_type ()))
{ {
asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM); asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
return; return;
...@@ -23209,7 +23262,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr) ...@@ -23209,7 +23262,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM); asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
/* Return to caller. */ /* Return to caller. */
asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr); if (IS_CMSE_ENTRY (arm_current_func_type ()))
asm_fprintf (f, "\tbxns\t%r\n", 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. /* Scan INSN just before assembler is output for it.
...@@ -24095,6 +24151,12 @@ thumb2_expand_return (bool simple_return) ...@@ -24095,6 +24151,12 @@ thumb2_expand_return (bool simple_return)
if (!simple_return && saved_regs_mask) 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 assert 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) if (num_regs == 1)
{ {
rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2)); rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
...@@ -24512,6 +24574,7 @@ arm_expand_epilogue (bool really_return) ...@@ -24512,6 +24574,7 @@ arm_expand_epilogue (bool really_return)
if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
&& (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL) && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
&& !IS_CMSE_ENTRY (func_type)
&& !IS_STACKALIGN (func_type) && !IS_STACKALIGN (func_type)
&& really_return && really_return
&& crtl->args.pretend_args_size == 0 && crtl->args.pretend_args_size == 0
......
...@@ -75,16 +75,7 @@ ...@@ -75,16 +75,7 @@
/* We might need a ARM specific header to function declarations. */ /* We might need a ARM specific header to function declarations. */
#undef ASM_DECLARE_FUNCTION_NAME #undef ASM_DECLARE_FUNCTION_NAME
#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ #define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
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)
/* We might need an ARM specific trailer for function declarations. */ /* We might need an ARM specific trailer for function declarations. */
#undef ASM_DECLARE_FUNCTION_SIZE #undef ASM_DECLARE_FUNCTION_SIZE
......
2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com> 2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com>
Thomas Preud'homme <thomas.preudhomme@arm.com> Thomas Preud'homme <thomas.preudhomme@arm.com>
* gcc.target/arm/cmse/cmse-4.c: New.
* gcc.target/arm/cmse/cmse-9.c: New.
* gcc.target/arm/cmse/cmse-10.c: New.
2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com>
Thomas Preud'homme <thomas.preudhomme@arm.com>
* gcc.target/arm/cmse/cmse-3.c: New. * gcc.target/arm/cmse/cmse-3.c: New.
2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com> 2016-12-02 Andre Vieira <andre.simoesdiasvieira@arm.com>
......
/* { dg-do compile } */
/* { 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:" } } */
/* { dg-do compile } */
/* { 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:" } } */
/* { dg-do compile } */
/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } } */
int __attribute__ ((cmse_nonsecure_entry))
foo (int a)
{ /* { dg-warning "attribute ignored without -mcmse option" } */
return a + 1;
}
/* { dg-final { scan-assembler "foo:" } } */
/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment