[PATCH][ARM] Add support for "noinit" attribute
Richard Earnshaw
Richard.Earnshaw@arm.com
Tue Jul 2 10:30:00 GMT 2019
On 02/07/2019 11:13, Richard Earnshaw wrote:
>
>
> On 02/07/2019 09:39, Richard Earnshaw wrote:
>>
>>
>> On 01/07/2019 16:58, Kyrill Tkachov wrote:
>>> Hi Christophe,
>>>
>>> On 6/13/19 4:13 PM, Christophe Lyon wrote:
>>>> Hi,
>>>>
>>>> Similar to what already exists for TI msp430 or in TI compilers for
>>>> arm, this patch adds support for "noinit" attribute for arm. It's very
>>>> similar to the corresponding code in GCC for msp430.
>>>>
>>>> It is useful for embedded targets where the user wants to keep the
>>>> value of some data when the program is restarted: such variables are
>>>> not zero-initialized.It is mostly a helper/shortcut to placing
>>>> variables in a dedicated section.
>>>>
>>>> It's probably desirable to add the following chunk to the GNU linker:
>>>> diff --git a/ld/emulparams/armelf.sh b/ld/emulparams/armelf.sh
>>>> index 272a8bc..9555cec 100644
>>>> --- a/ld/emulparams/armelf.sh
>>>> +++ b/ld/emulparams/armelf.sh
>>>> @@ -10,7 +10,19 @@ OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7)
>>>> *(.vfp11_veneer) *(.v4_bx)'
>>>> Â OTHER_BSS_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__bss_start__ =
>>>> .${CREATE_SHLIB+)};"
>>>> Â OTHER_BSS_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}_bss_end__ =
>>>> .${CREATE_SHLIB+)}; ${CREATE_SHLIB+PROVIDE (}__bss_end__ =
>>>> .${CREATE_SHLIB+)};"
>>>> Â OTHER_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__end__ =
>>>> .${CREATE_SHLIB+)};"
>>>> -OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP
>>>> (*(.note.gnu.arm.ident)) }'
>>>> +OTHER_SECTIONS='
>>>> +.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
>>>> +Â /* This section contains data that is not initialised during load
>>>> +    *or* application reset. */
>>>> +Â Â .noinit (NOLOAD) :
>>>> +Â Â {
>>>> +Â Â Â Â . = ALIGN(2);
>>>> +Â Â Â Â PROVIDE (__noinit_start = .);
>>>> +Â Â Â Â *(.noinit)
>>>> +Â Â Â Â . = ALIGN(2);
>>>> +Â Â Â Â PROVIDE (__noinit_end = .);
>>>> +Â Â }
>>>> +'
>>>>
>>>> so that the noinit section has the "NOLOAD" flag.
>>>>
>>>> I'll submit that part separately to the binutils project if OK.
>>>>
>>>> OK?
>>>>
>>>
>>> This is mostly ok by me, with a few code comments inline.
>>>
>>> I wonder whether this is something we could implement for all targets
>>> in the midend, but this would require linker script support for the
>>> target to be effective...
>>
>> Can't this be done using named sections? If the sections were of the
>> form .bss.<foo> then it would be easy to make linker scripts do
>> something sane by default and users could filter them out to special
>> noinit sections if desired.
>>
>
> To answer my own question, it would appear to be yes. You can write today:
>
> int xxx __attribute__ ((section (".bss.noinit")));
>
> int main ()
> {
> Â return xxx;
> }
>
> And the compiler will generate
>     .section   .bss.noinit,"aw",@nobits
> Â Â Â Â .align 4
>     .type   xxx, @object
>     .size   xxx, 4
> xxx:
>     .zero   4
>
> So at this point, all you need is a linker script to filter .bss.noinit
> into your special part of the final image.
>
> This will most likely work today on any GCC target that supports named
> sections, which is pretty much all of them these days.
>
Alternatively, we already have:
https://gcc.gnu.org/ml/gcc-patches/2014-09/msg01302.html
R.
> R.
>
>> R.
>>
>>>
>>> Thanks,
>>>
>>> Kyrill
>>>
>>>> Thanks,
>>>>
>>>> Christophe
>>>
>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>> index e3e71ea..332c41b 100644
>>> --- a/gcc/config/arm/arm.c
>>> +++ b/gcc/config/arm/arm.c
>>> @@ -151,6 +151,7 @@ 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 tree arm_data_attr (tree *, tree, tree, int, bool *);
>>> Â Â static void arm_output_function_epilogue (FILE *);
>>> Â Â static void arm_output_function_prologue (FILE *);
>>> Â Â static int arm_comp_type_attributes (const_tree, const_tree);
>>> @@ -375,7 +376,8 @@ static const struct attribute_spec
>>> arm_attribute_table[] =
>>> Â Â Â Â Â arm_handle_cmse_nonsecure_entry, NULL },
>>> Â Â Â { "cmse_nonsecure_call", 0, 0, true, false, false, true,
>>> Â Â Â Â Â arm_handle_cmse_nonsecure_call, NULL },
>>> -Â { NULL, 0, 0, false, false, false, false, NULL, NULL }
>>> +Â { "noinit", 0, 0, true, false, false, false, arm_data_attr, NULL },
>>> +Â { NULL, 0, 0, false, false, false, false, NULL, NULL },
>>> Â Â };
>>>
>>>   /* Initialize the GCC target structure. */
>>> @@ -808,6 +810,10 @@ static const struct attribute_spec
>>> arm_attribute_table[] =
>>>
>>> Â Â #undef TARGET_CONSTANT_ALIGNMENT
>>> Â Â #define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
>>> +
>>> +#undef TARGET_ASM_SELECT_SECTION
>>> +#define TARGET_ASM_SELECT_SECTION arm_select_section
>>> +
>>>
>>>   /* Obstack for minipool constant handling. */
>>> Â Â static struct obstack minipool_obstack;
>>> @@ -7150,6 +7156,47 @@ arm_handle_cmse_nonsecure_call (tree *node,
>>> tree name,
>>> Â Â Â return NULL_TREE;
>>> Â Â }
>>>
>>> +/* Called when the noinit attribute is used. Check whether the
>>> +Â Â attribute is allowed here and add the attribute to the variable
>>> +Â Â decl tree or otherwise issue a diagnostic. This function checks
>>> +Â Â NODE is of the expected type and issues diagnostics otherwise using
>>> +  NAME. If it is not of the expected type *NO_ADD_ATTRS will be set
>>> +  to true. */
>>> +
>>> +static tree
>>> +arm_data_attr (tree * node,
>>> +         tree  name,
>>> +         tree  args ATTRIBUTE_UNUSED,
>>> +         int   flags ATTRIBUTE_UNUSED,
>>> +Â Â Â Â Â Â Â Â Â bool * no_add_attrs ATTRIBUTE_UNUSED)
>>> +{
>>>
>>> no_add_attrs is set in this function, so should not be ATTRIBUTE_UNUSED?
>>> Arguably args is also checked against NULL, so it's technically not
>>> unused either.
>>>
>>> +Â const char * message = NULL;
>>> +
>>> +Â gcc_assert (DECL_P (* node));
>>>
>>> The house style doesn't have a space after '*'. Same elsewhere in the
>>> patch.
>>>
>>> +Â gcc_assert (args == NULL);
>>> +
>>> +Â if (TREE_CODE (* node) != VAR_DECL)
>>> +Â Â Â message = G_("%qE attribute only applies to variables");
>>> +
>>> + /* Check that it's possible for the variable to have a section. */
>>> +Â if ((TREE_STATIC (* node) || DECL_EXTERNAL (* node) || in_lto_p)
>>> +Â Â Â Â Â && DECL_SECTION_NAME (* node))
>>> +Â Â Â message = G_("%qE attribute cannot be applied to variables with
>>> specific sections");
>>> +
>>> + /* If this var is thought to be common, then change this. Common
>>> variables
>>> +Â Â Â Â are assigned to sections before the backend has a chance to
>>> process them. */
>>> +Â if (DECL_COMMON (* node))
>>> +Â Â Â DECL_COMMON (* node) = 0;
>>> +
>>> +Â if (message)
>>> +Â Â Â {
>>> +Â Â Â Â Â warning (OPT_Wattributes, message, name);
>>> +Â Â Â Â Â * no_add_attrs = true;
>>> +Â Â Â }
>>> +
>>> +Â 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). */
>>> @@ -27890,6 +27937,8 @@ arm_asm_emit_except_personality (rtx
>>> personality)
>>>
>>>   /* Implement TARGET_ASM_INITIALIZE_SECTIONS. */
>>>
>>> +static section *noinit_section;
>>> +
>>> Â Â static void
>>> Â Â arm_asm_init_sections (void)
>>> Â Â {
>>> @@ -27902,6 +27951,19 @@ arm_asm_init_sections (void)
>>> Â Â Â if (target_pure_code)
>>> Â Â Â Â Â text_section->unnamed.data = "\t.section
>>> .text,\"0x20000006\",%progbits";
>>> Â Â #endif
>>> +
>>> +Â noinit_section = get_unnamed_section (0, output_section_asm_op,
>>> ".section .noinit,\"aw\"");
>>> +}
>>> +
>>> +static section *
>>> +arm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
>>> +{
>>>
>>> Please add a function comment.
>>>
>>> +Â gcc_assert (decl != NULL_TREE);
>>> +
>>> +Â if (DECL_P (decl) && lookup_attribute ("noinit", DECL_ATTRIBUTES
>>> (decl)) != NULL_TREE)
>>> +Â Â Â return noinit_section;
>>> +Â else
>>> +Â Â Â return default_elf_select_section (decl, reloc, align);
>>> Â Â }
>>>
>>>   /* Output unwind directives for the start/end of a function. */
>>> @@ -31520,6 +31582,9 @@ arm_elf_section_type_flags (tree decl, const
>>> char *name, int reloc)
>>> Â Â Â if (decl && TREE_CODE (decl) == FUNCTION_DECL && target_pure_code)
>>> Â Â Â Â Â flags |= SECTION_ARM_PURECODE;
>>>
>>> +Â if (strcmp (name, ".noinit") == 0)
>>> +Â Â Â flags = SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
>>> +
>>>
>>>
>>> You're overwriting the flags here. Are you sure you don't want "flags
>>> |= ..." here?
>>>
>>>
>>> Â Â return flags;
>>> Â Â }
>>>
>>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>>> index 2520835..d544527 100644
>>> --- a/gcc/doc/extend.texi
>>> +++ b/gcc/doc/extend.texi
>>> @@ -6684,6 +6684,7 @@ attributes.
>>> Â Â @menu
>>> Â Â * Common Variable Attributes::
>>> Â Â * ARC Variable Attributes::
>>> +* ARM Variable Attributes::
>>> Â Â * AVR Variable Attributes::
>>> Â Â * Blackfin Variable Attributes::
>>> Â Â * H8/300 Variable Attributes::
>>> @@ -7131,6 +7132,18 @@ given via attribute argument.
>>>
>>> Â Â @end table
>>>
>>> +@node ARM Variable Attributes
>>> +@subsection ARM Variable Attributes
>>> +
>>> +@table @code
>>> +@item noinit
>>> +@cindex @code{noinit} variable attribute, ARM
>>> +Any data with the @code{noinit} attribute will not be initialised by
>>> +the C runtime startup code, or the program loader. Not initialising
>>> +data in this way can reduce program startup times.
>>> +
>>> +@end table
>>> +
>>> Â Â @node AVR Variable Attributes
>>> Â Â @subsection AVR Variable Attributes
>>>
>>> diff --git a/gcc/testsuite/gcc.target/arm/data-attributes.c
>>> b/gcc/testsuite/gcc.target/arm/data-attributes.c
>>> new file mode 100644
>>> index 0000000..323c8e0
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/arm/data-attributes.c
>>> @@ -0,0 +1,51 @@
>>> +/* { dg-do run { target { ! *-*-linux* } } } */
>>> +/* { dg-options "-O2" } */
>>> +
>>> +/* This test checks that noinit data is handled correctly. */
>>> +
>>> +extern void _start (void) __attribute__ ((noreturn));
>>> +extern void abort (void) __attribute__ ((noreturn));
>>> +extern void exit (int) __attribute__ ((noreturn));
>>> +
>>> +int var_common;
>>> +int var_zero = 0;
>>> +int var_one = 1;
>>> +int __attribute__((noinit)) var_noinit;
>>> +int var_init = 2;
>>> +
>>> +int
>>> +main (void)
>>> +{
>>> +Â /* Make sure that the C startup code has correctly initialised the
>>> ordinary variables. */
>>> +Â if (var_common != 0)
>>> +Â Â Â abort ();
>>> +
>>> +Â /* Initialised variables are not re-initialised during startup, so
>>> check their original values only during the first run of this test. */
>>> +Â if (var_init == 2)
>>> +Â Â Â if (var_zero != 0 || var_one != 1)
>>> +Â Â Â Â Â abort ();
>>> +
>>> +Â switch (var_init)
>>> +Â Â Â {
>>> +Â Â Â case 2:
>>> +     /* First time through - change all the values. */
>>> +Â Â Â Â Â var_common = var_zero = var_one = var_noinit = var_init = 3;
>>> +Â Â Â Â Â break;
>>> +
>>> +Â Â Â case 3:
>>> +     /* Second time through - make sure that d has not been reset. */
>>> +Â Â Â Â Â if (var_noinit != 3)
>>> +Â Â Â abort ();
>>> +Â Â Â Â Â exit (0);
>>> +
>>> +Â Â Â default:
>>> +     /* Any other value for var_init is an error. */
>>> +Â Â Â Â Â abort ();
>>> +Â Â Â }
>>> +
>>> + /* Simulate a processor reset by calling the C startup code. */
>>> +Â _start ();
>>> +
>>> + /* Should never reach here. */
>>> +Â abort ();
>>> +}
>>>
More information about the Gcc-patches
mailing list