[PATCH][ARM] Add support for "noinit" attribute
Richard Earnshaw
Richard.Earnshaw@arm.com
Tue Jul 2 08:44:00 GMT 2019
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.
>
Oh, and the tests need to handle the other OSs we support that won't
support this extension. The list is longer than just 'linux'
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