Message ID | 001501d13f80$19939080$4cbab180$@foss.arm.com |
---|---|
State | New |
Headers | show |
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 --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:" } } */