Commit f0033821 by Christophe Lyon Committed by Christophe Lyon

Add generic support for noinit attribute.

    Similar to what already exists for TI msp430 or in TI compilers for
    arm, this patch adds support for the "noinit" attribute.

    It is convenient 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 added a testcase if gcc.c-torture/execute, gated by the new noinit
    effective-target.

    Finally, I tested on arm-eabi, but not on msp430 for which I do not
    have the environment.

gcc/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

	* doc/extend.texi: Add "noinit" attribute documentation.
	* doc/sourcebuild.texi: Add noinit effective target documentation.
	* varasm.c (default_section_type_flags): Add support for "noinit" section.
	(default_elf_select_section): Add support for "noinit" attribute.
	* config/msp430/msp430.c (msp430_attribute_table): Remove "noinit" entry.

gcc/c-family/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

	* c-attribs.c (c_common_attribute_table): Add "noinit" entry. Add
	exclusion with "section" attribute.
	(attr_noinit_exclusions): New table.
	(handle_noinit_attribute): New function.

gcc/testsuite/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

	* lib/target-supports.exp (check_effective_target_noinit): New
	proc.
	* gcc.c-torture/execute/noinit-attribute.c: New test.

From-SVN: r274482
parent 93cf5515
2019-08-14 Christophe Lyon <christophe.lyon@linaro.org>
* doc/extend.texi: Add "noinit" attribute documentation.
* doc/sourcebuild.texi: Add noinit effective target documentation.
* varasm.c (default_section_type_flags): Add support for "noinit"
section.
(default_elf_select_section): Add support for "noinit" attribute.
* config/msp430/msp430.c (msp430_attribute_table): Remove "noinit" entry.
2019-08-14 Richard Biener <rguenther@suse.de> 2019-08-14 Richard Biener <rguenther@suse.de>
Uroš Bizjak <ubizjak@gmail.com> Uroš Bizjak <ubizjak@gmail.com>
......
2019-08-14 Christophe Lyon <christophe.lyon@linaro.org>
* c-attribs.c (c_common_attribute_table): Add "noinit" entry. Add
exclusion with "section" attribute.
(attr_noinit_exclusions): New table.
(handle_noinit_attribute): New function.
2019-08-13 Richard Sandiford <richard.sandiford@arm.com> 2019-08-13 Richard Sandiford <richard.sandiford@arm.com>
PR middle-end/91421 PR middle-end/91421
......
...@@ -92,6 +92,7 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *); ...@@ -92,6 +92,7 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *);
static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree, static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
int, bool *); int, bool *);
static tree handle_noinit_attribute (tree *, tree, tree, int, bool *);
static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ; static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *); static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
...@@ -235,6 +236,13 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = ...@@ -235,6 +236,13 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
ATTR_EXCL (NULL, false, false, false) ATTR_EXCL (NULL, false, false, false)
}; };
static const struct attribute_spec::exclusions attr_noinit_exclusions[] =
{
ATTR_EXCL ("noinit", true, true, true),
ATTR_EXCL ("section", true, true, true),
ATTR_EXCL (NULL, false, false, false),
};
/* Table of machine-independent attributes common to all C-like languages. /* Table of machine-independent attributes common to all C-like languages.
Current list of processed common attributes: nonnull. */ Current list of processed common attributes: nonnull. */
...@@ -307,7 +315,7 @@ const struct attribute_spec c_common_attribute_table[] = ...@@ -307,7 +315,7 @@ const struct attribute_spec c_common_attribute_table[] =
{ "mode", 1, 1, false, true, false, false, { "mode", 1, 1, false, true, false, false,
handle_mode_attribute, NULL }, handle_mode_attribute, NULL },
{ "section", 1, 1, true, false, false, false, { "section", 1, 1, true, false, false, false,
handle_section_attribute, NULL }, handle_section_attribute, attr_noinit_exclusions },
{ "aligned", 0, 1, false, false, false, false, { "aligned", 0, 1, false, false, false, false,
handle_aligned_attribute, handle_aligned_attribute,
attr_aligned_exclusions }, attr_aligned_exclusions },
...@@ -458,6 +466,8 @@ const struct attribute_spec c_common_attribute_table[] = ...@@ -458,6 +466,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_nocf_check_attribute, NULL }, handle_nocf_check_attribute, NULL },
{ "copy", 1, 1, false, false, false, false, { "copy", 1, 1, false, false, false, false,
handle_copy_attribute, NULL }, handle_copy_attribute, NULL },
{ "noinit", 0, 0, true, false, false, false,
handle_noinit_attribute, attr_noinit_exclusions },
{ NULL, 0, 0, false, false, false, false, NULL, NULL } { NULL, 0, 0, false, false, false, false, NULL, NULL }
}; };
...@@ -2224,6 +2234,54 @@ handle_weak_attribute (tree *node, tree name, ...@@ -2224,6 +2234,54 @@ handle_weak_attribute (tree *node, tree name,
return NULL_TREE; return NULL_TREE;
} }
/* Handle a "noinit" attribute; arguments as in struct
attribute_spec.handler. 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
handle_noinit_attribute (tree * node,
tree name,
tree args,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
const char *message = NULL;
gcc_assert (DECL_P (*node));
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. */
else 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");
else if (!targetm.have_switchable_bss_sections)
message = G_("%qE attribute is specific to ELF targets");
if (message)
{
warning (OPT_Wattributes, message, name);
*no_add_attrs = true;
}
else
/* 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. Do this only if the attribute is
valid. */
if (DECL_COMMON (*node))
DECL_COMMON (*node) = 0;
return NULL_TREE;
}
/* Handle a "noplt" attribute; arguments as in /* Handle a "noplt" attribute; arguments as in
struct attribute_spec.handler. */ struct attribute_spec.handler. */
......
...@@ -1521,8 +1521,6 @@ const struct attribute_spec msp430_attribute_table[] = ...@@ -1521,8 +1521,6 @@ const struct attribute_spec msp430_attribute_table[] =
{ ATTR_EITHER, 0, 0, true, false, false, false, msp430_section_attr, { ATTR_EITHER, 0, 0, true, false, false, false, msp430_section_attr,
NULL }, NULL },
{ ATTR_NOINIT, 0, 0, true, false, false, false, msp430_data_attr,
NULL },
{ ATTR_PERSIST, 0, 0, true, false, false, false, msp430_data_attr, { ATTR_PERSIST, 0, 0, true, false, false, false, msp430_data_attr,
NULL }, NULL },
...@@ -1751,6 +1749,8 @@ msp430_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) ...@@ -1751,6 +1749,8 @@ msp430_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
{ {
if (TREE_CODE (decl) == FUNCTION_DECL) if (TREE_CODE (decl) == FUNCTION_DECL)
return text_section; return text_section;
/* FIXME: ATTR_NOINIT is handled generically in
default_elf_select_section. */
else if (has_attr (ATTR_NOINIT, decl)) else if (has_attr (ATTR_NOINIT, decl))
return noinit_section; return noinit_section;
else if (has_attr (ATTR_PERSIST, decl)) else if (has_attr (ATTR_PERSIST, decl))
......
...@@ -7156,6 +7156,14 @@ The @code{visibility} attribute is described in ...@@ -7156,6 +7156,14 @@ The @code{visibility} attribute is described in
The @code{weak} attribute is described in The @code{weak} attribute is described in
@ref{Common Function Attributes}. @ref{Common Function Attributes}.
@item noinit
@cindex @code{noinit} variable attribute
Any data with the @code{noinit} attribute will not be initialized by
the C runtime startup code, or the program loader. Not initializing
data in this way can reduce program startup times. This attribute is
specific to ELF targets and relies on the linker to place such data in
the right location
@end table @end table
@node ARC Variable Attributes @node ARC Variable Attributes
......
...@@ -2302,6 +2302,9 @@ Target uses natural alignment (aligned to type size) for types of ...@@ -2302,6 +2302,9 @@ Target uses natural alignment (aligned to type size) for types of
Target uses natural alignment (aligned to type size) for types of Target uses natural alignment (aligned to type size) for types of
64 bits or less. 64 bits or less.
@item noinit
Target supports the @code{noinit} variable attribute.
@item nonpic @item nonpic
Target does not generate PIC by default. Target does not generate PIC by default.
......
2019-08-14 Christophe Lyon <christophe.lyon@linaro.org>
* lib/target-supports.exp (check_effective_target_noinit): New
proc.
* gcc.c-torture/execute/noinit-attribute.c: New test.
2019-08-14 Richard Biener <rguenther@suse.de> 2019-08-14 Richard Biener <rguenther@suse.de>
PR target/91154 PR target/91154
......
/* { dg-do run } */
/* { dg-require-effective-target noinit */
/* { 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 __attribute__((noinit)) func(); /* { dg-warning "attribute only applies to variables" } */
int __attribute__((section ("mysection"), noinit)) var_section1; /* { dg-warning "because it conflicts with attribute" } */
int __attribute__((noinit, section ("mysection"))) var_section2; /* { dg-warning "because it conflicts with attribute" } */
int
main (void)
{
/* Make sure that the C startup code has correctly initialized the ordinary variables. */
if (var_common != 0)
abort ();
/* Initialized variables are not re-initialized 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 ();
}
...@@ -364,6 +364,18 @@ proc check_weak_override_available { } { ...@@ -364,6 +364,18 @@ proc check_weak_override_available { } {
return [check_weak_available] return [check_weak_available]
} }
# The noinit attribute is only supported by some targets.
# This proc returns 1 if it's supported, 0 if it's not.
proc check_effective_target_noinit { } {
if { [istarget arm*-*-eabi]
|| [istarget msp430-*-*] } {
return 1
}
return 0
}
############################### ###############################
# proc check_visibility_available { what_kind } # proc check_visibility_available { what_kind }
############################### ###############################
......
...@@ -6430,6 +6430,9 @@ default_section_type_flags (tree decl, const char *name, int reloc) ...@@ -6430,6 +6430,9 @@ default_section_type_flags (tree decl, const char *name, int reloc)
|| strncmp (name, ".gnu.linkonce.tb.", 17) == 0) || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
flags |= SECTION_TLS | SECTION_BSS; flags |= SECTION_TLS | SECTION_BSS;
if (strcmp (name, ".noinit") == 0)
flags |= SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
/* Various sections have special ELF types that the assembler will /* Various sections have special ELF types that the assembler will
assign by default based on the name. They are neither SHT_PROGBITS assign by default based on the name. They are neither SHT_PROGBITS
nor SHT_NOBITS, so when changing sections we don't want to print a nor SHT_NOBITS, so when changing sections we don't want to print a
...@@ -6755,6 +6758,7 @@ default_elf_select_section (tree decl, int reloc, ...@@ -6755,6 +6758,7 @@ default_elf_select_section (tree decl, int reloc,
unsigned HOST_WIDE_INT align) unsigned HOST_WIDE_INT align)
{ {
const char *sname; const char *sname;
switch (categorize_decl_for_section (decl, reloc)) switch (categorize_decl_for_section (decl, reloc))
{ {
case SECCAT_TEXT: case SECCAT_TEXT:
...@@ -6792,6 +6796,13 @@ default_elf_select_section (tree decl, int reloc, ...@@ -6792,6 +6796,13 @@ default_elf_select_section (tree decl, int reloc,
sname = ".tdata"; sname = ".tdata";
break; break;
case SECCAT_BSS: case SECCAT_BSS:
if (DECL_P (decl)
&& lookup_attribute ("noinit", DECL_ATTRIBUTES (decl)) != NULL_TREE)
{
sname = ".noinit";
break;
}
if (bss_section) if (bss_section)
return bss_section; return bss_section;
sname = ".bss"; sname = ".bss";
......
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