aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/c-attribs.c141
-rw-r--r--gcc/doc/extend.texi20
-rw-r--r--gcc/doc/sourcebuild.texi3
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-noinit-1.c7
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-noinit-2.c8
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-noinit-3.c11
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-noinit-invalid.c12
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-noinit-main.inc (renamed from gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c)37
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-persistent-1.c8
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-persistent-2.c8
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-persistent-3.c10
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-persistent-invalid.c11
-rw-r--r--gcc/testsuite/c-c++-common/torture/attr-persistent-main.inc58
-rw-r--r--gcc/testsuite/lib/target-supports.exp12
-rw-r--r--gcc/tree.h7
-rw-r--r--gcc/varasm.c19
16 files changed, 303 insertions, 69 deletions
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 1d2ab7c..6d515dc 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -94,10 +94,10 @@ static tree handle_constructor_attribute (tree *, tree, tree, int, bool *);
static tree handle_destructor_attribute (tree *, tree, tree, int, bool *);
static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
static tree handle_section_attribute (tree *, tree, tree, int, bool *);
+static tree handle_special_var_sec_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,
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_noplt_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -248,9 +248,12 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
ATTR_EXCL (NULL, false, false, false)
};
-static const struct attribute_spec::exclusions attr_noinit_exclusions[] =
+/* Exclusions that apply to attributes that put declarations in specific
+ sections. */
+static const struct attribute_spec::exclusions attr_section_exclusions[] =
{
ATTR_EXCL ("noinit", true, true, true),
+ ATTR_EXCL ("persistent", true, true, true),
ATTR_EXCL ("section", true, true, true),
ATTR_EXCL (NULL, false, false, false),
};
@@ -339,7 +342,7 @@ const struct attribute_spec c_common_attribute_table[] =
{ "mode", 1, 1, false, true, false, false,
handle_mode_attribute, NULL },
{ "section", 1, 1, true, false, false, false,
- handle_section_attribute, attr_noinit_exclusions },
+ handle_section_attribute, attr_section_exclusions },
{ "aligned", 0, 1, false, false, false, false,
handle_aligned_attribute,
attr_aligned_exclusions },
@@ -509,7 +512,9 @@ const struct attribute_spec c_common_attribute_table[] =
{ "copy", 1, 1, false, false, false, false,
handle_copy_attribute, NULL },
{ "noinit", 0, 0, true, false, false, false,
- handle_noinit_attribute, attr_noinit_exclusions },
+ handle_special_var_sec_attribute, attr_section_exclusions },
+ { "persistent", 0, 0, true, false, false, false,
+ handle_special_var_sec_attribute, attr_section_exclusions },
{ "access", 1, 3, false, true, true, false,
handle_access_attribute, NULL },
/* Attributes used by Objective-C. */
@@ -2387,64 +2392,112 @@ handle_weak_attribute (tree *node, tree name,
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. */
-
+/* Handle a "noinit" or "persistent" attribute; arguments as in
+ struct attribute_spec.handler.
+ This generic handler is used for "special variable sections" that allow the
+ section name to be set using a dedicated attribute. Additional validation
+ is performed for the specific properties of the section corresponding to the
+ attribute.
+ The ".noinit" section *is not* loaded by the program loader, and is not
+ initialized by the runtime startup code.
+ The ".persistent" section *is* loaded by the program loader, but is not
+ initialized by the runtime startup code. */
static tree
-handle_noinit_attribute (tree * node,
- tree name,
- tree args,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
+handle_special_var_sec_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
{
- const char *message = NULL;
+ tree decl = *node;
tree res = NULL_TREE;
- gcc_assert (DECL_P (*node));
- gcc_assert (args == NULL);
+ /* First perform generic validation common to "noinit" and "persistent"
+ attributes. */
+ if (!targetm_common.have_named_sections)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "section attributes are not supported for this target");
+ goto fail;
+ }
- if (TREE_CODE (*node) != VAR_DECL)
- message = G_("%qE attribute only applies to variables");
+ if (!VAR_P (decl))
+ {
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
+ "ignoring %qE attribute not set on a variable",
+ name);
+ goto fail;
+ }
- /* 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");
+ if (VAR_P (decl)
+ && current_function_decl != NULL_TREE
+ && !TREE_STATIC (decl))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute cannot be specified for local variables",
+ name);
+ goto fail;
+ }
- else if (!targetm.have_switchable_bss_sections)
- message = G_("%qE attribute is specific to ELF targets");
+ if (VAR_P (decl)
+ && !targetm.have_tls && targetm.emutls.tmpl_section
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ error ("section of %q+D cannot be overridden", decl);
+ goto fail;
+ }
- if (message)
+ if (!targetm.have_switchable_bss_sections)
{
- warning (OPT_Wattributes, message, name);
- *no_add_attrs = true;
+ error ("%qE attribute is specific to ELF targets", name);
+ goto fail;
}
- else
+
+ if (TREE_READONLY (decl))
+ {
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
+ "ignoring %qE attribute set on const variable",
+ name);
+ goto fail;
+ }
+
+ /* Now validate noinit/persistent individually. */
+ if (strcmp (IDENTIFIER_POINTER (name), "noinit") == 0)
+ {
+ if (DECL_INITIAL (decl))
+ {
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
+ "ignoring %qE attribute set on initialized variable",
+ name);
+ goto fail;
+ }
+ /* If this var is thought to be common, then change this. "noinit"
+ variables must be placed in an explicit ".noinit" section. */
+ DECL_COMMON (decl) = 0;
+ }
+ else if (strcmp (IDENTIFIER_POINTER (name), "persistent") == 0)
{
- res = targetm.handle_generic_attribute (node, name, args, flags,
- no_add_attrs);
- /* If the back end confirms the attribute can be added then continue onto
- final processing. */
- if (!(*no_add_attrs))
+ if (DECL_COMMON (decl) || DECL_INITIAL (decl) == NULL_TREE)
{
- /* 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;
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
+ "ignoring %qE attribute set on uninitialized variable",
+ name);
+ goto fail;
}
}
+ else
+ gcc_unreachable ();
+
+ res = targetm.handle_generic_attribute (node, name, args, flags,
+ no_add_attrs);
+
+ /* If the back end confirms the attribute can be added then continue onto
+ final processing. */
+ if (!(*no_add_attrs))
+ return res;
+fail:
+ *no_add_attrs = true;
return res;
}
-
/* Handle a "noplt" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f026942..6018347 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7426,9 +7426,23 @@ The @code{weak} attribute is described in
@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
+data in this way can reduce program startup times.
+
+This attribute is specific to ELF targets and relies on the linker
+script to place sections with the @code{.noinit} prefix in the right
+location.
+
+@item persistent
+@cindex @code{persistent} variable attribute
+Any data with the @code{persistent} attribute will not be initialized by
+the C runtime startup code, but will be initialized by the program
+loader. This enables the value of the variable to @samp{persist}
+between processor resets.
+
+This attribute is specific to ELF targets and relies on the linker
+script to place the sections with the @code{.persistent} prefix in the
+right location. Specifically, some type of non-volatile, writeable
+memory is required.
@item objc_nullability (@var{nullability kind}) @r{(Objective-C and Objective-C++ only)}
@cindex @code{objc_nullability} variable attribute
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 566fda0..852eaa2 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2548,6 +2548,9 @@ Target does not generate PIC by default.
@item offload_gcn
Target has been configured for OpenACC/OpenMP offloading on AMD GCN.
+@item persistent
+Target supports the @code{persistent} variable attribute.
+
@item pie_enabled
Target generates PIE by default.
diff --git a/gcc/testsuite/c-c++-common/torture/attr-noinit-1.c b/gcc/testsuite/c-c++-common/torture/attr-noinit-1.c
new file mode 100644
index 0000000..877e764
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-noinit-1.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-require-effective-target noinit } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-options "-save-temps" } */
+/* { dg-final { scan-assembler ".section\t.noinit,\"aw\"\n" } } */
+
+#include "attr-noinit-main.inc"
diff --git a/gcc/testsuite/c-c++-common/torture/attr-noinit-2.c b/gcc/testsuite/c-c++-common/torture/attr-noinit-2.c
new file mode 100644
index 0000000..befa2a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-noinit-2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target noinit } */
+/* { dg-options "-fdata-sections -save-temps" } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-final { scan-assembler ".section\t.noinit.var_noinit,\"aw\"\n" } } */
+
+/* Test the "noinit" attribute with -fdata-sections. */
+#include "attr-noinit-main.inc"
diff --git a/gcc/testsuite/c-c++-common/torture/attr-noinit-3.c b/gcc/testsuite/c-c++-common/torture/attr-noinit-3.c
new file mode 100644
index 0000000..519e88a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-noinit-3.c
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-require-effective-target noinit } */
+/* { dg-options "-flto -save-temps" } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-final { scan-file attr-noinit-3.ltrans0.ltrans.s ".section\t\.noinit,\"aw\"\n" } } */
+
+/* Test the "noinit" attribute with -flto. Specifically examine the
+ final LTO assembly file, to ensure the "noinit" setting on the variable
+ hasn't been lost. */
+#include "attr-noinit-main.inc"
+
diff --git a/gcc/testsuite/c-c++-common/torture/attr-noinit-invalid.c b/gcc/testsuite/c-c++-common/torture/attr-noinit-invalid.c
new file mode 100644
index 0000000..c3b5fff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-noinit-invalid.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target noinit } */
+/* { dg-options "-Wattributes" } */
+
+/* Check warning/error messages for "noinit" attribute misuse. */
+int __attribute__((noinit)) noinit_fn (void); /* { dg-warning "ignoring 'noinit' attribute not set on a variable" } */
+int __attribute__((section ("mysection"), noinit)) noinit_section1; /* { dg-warning "because it conflicts with attribute" } */
+int __attribute__((noinit, section ("mysection"))) noinit_section2; /* { dg-warning "because it conflicts with attribute" } */
+const int __attribute__((noinit)) noinit_const; /* { dg-warning "ignoring 'noinit' attribute set on const variable" } */
+/* { dg-error "uninitialized 'const noinit_const'" "" { target c++ } .-1 } */
+int __attribute__((noinit)) noinit_init = 42; /* { dg-warning "ignoring 'noinit' attribute set on initialized variable" } */
+void foo (void) { int __attribute__((noinit)) local_noinit; } /* { dg-error "'noinit' attribute cannot be specified for local variables" } */
diff --git a/gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c b/gcc/testsuite/c-c++-common/torture/attr-noinit-main.inc
index c8fa22b..92cdb9b 100644
--- a/gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c
+++ b/gcc/testsuite/c-c++-common/torture/attr-noinit-main.inc
@@ -1,16 +1,16 @@
-/* { dg-do run } */
-/* { dg-require-effective-target noinit } */
-/* { dg-options "-Wattributes" } */
-/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
-
-/* This test checks that noinit data is handled correctly.
+/* This test checks that data marked with the "noinit" attribute is handled
+ correctly.
If data LMA != VMA (e.g. for simulating the copy of data from ROM to RAM),
then var_init will always be re-initialized to 2 and this test will loop
- forever. */
+ forever, so it must be skipped for those targets. */
+#ifdef __cplusplus
+extern "C" {
+#endif
extern void _start (void) __attribute__ ((noreturn));
-extern void abort (void) __attribute__ ((noreturn));
-extern void exit (int) __attribute__ ((noreturn));
+#ifdef __cplusplus
+}
+#endif
int var_common;
int var_zero = 0;
@@ -18,24 +18,19 @@ 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 ();
+ __builtin_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 ();
+ __builtin_abort ();
switch (var_init)
{
@@ -45,19 +40,19 @@ main (void)
break;
case 3:
- /* Second time through - make sure that d has not been reset. */
+ /* Second time through - make sure that var_noinit has not been reset. */
if (var_noinit != 3)
- abort ();
- exit (0);
+ __builtin_abort ();
+ __builtin_exit (0);
default:
/* Any other value for var_init is an error. */
- abort ();
+ __builtin_abort ();
}
/* Simulate a processor reset by calling the C startup code. */
_start ();
/* Should never reach here. */
- abort ();
+ __builtin_abort ();
}
diff --git a/gcc/testsuite/c-c++-common/torture/attr-persistent-1.c b/gcc/testsuite/c-c++-common/torture/attr-persistent-1.c
new file mode 100644
index 0000000..72dc3c2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-persistent-1.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target persistent } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-options "-save-temps" } */
+/* { dg-final { scan-assembler ".section\t.persistent,\"aw\"\n" } } */
+
+/* Test the "persistent" attribute. */
+#include "attr-persistent-main.inc"
diff --git a/gcc/testsuite/c-c++-common/torture/attr-persistent-2.c b/gcc/testsuite/c-c++-common/torture/attr-persistent-2.c
new file mode 100644
index 0000000..a7de0d5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-persistent-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target persistent } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-options "-fdata-sections -save-temps" } */
+/* { dg-final { scan-assembler ".section\t.persistent.var_persistent,\"aw\"\n" } } */
+
+/* Test the "persistent" attribute with -fdata-sections. */
+#include "attr-persistent-main.inc"
diff --git a/gcc/testsuite/c-c++-common/torture/attr-persistent-3.c b/gcc/testsuite/c-c++-common/torture/attr-persistent-3.c
new file mode 100644
index 0000000..3e4fd28
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-persistent-3.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-require-effective-target persistent } */
+/* { dg-options "-flto -save-temps" } */
+/* { dg-skip-if "data LMA != VMA" { msp430-*-* } { "-mlarge" } } */
+/* { dg-final { scan-file attr-persistent-3.ltrans0.ltrans.s ".section\t\.persistent,\"aw\"\n" } } */
+
+/* Test the "persistent" attribute with -flto. Specifically examine the
+ final LTO assembly file, to ensure the "persistent" setting on the variable
+ hasn't been lost. */
+#include "attr-persistent-main.inc"
diff --git a/gcc/testsuite/c-c++-common/torture/attr-persistent-invalid.c b/gcc/testsuite/c-c++-common/torture/attr-persistent-invalid.c
new file mode 100644
index 0000000..06d9f35
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-persistent-invalid.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target persistent } */
+/* { dg-options "-Wattributes" } */
+
+/* Check warning/error messages for "persistent" attribute misuse. */
+int __attribute__((persistent)) persistent_fn (void); /* { dg-warning "ignoring 'persistent' attribute not set on a variable" } */
+int __attribute__((section ("mysection"), persistent)) persistent_section1 = 1; /* { dg-warning "because it conflicts with attribute" } */
+int __attribute__((persistent, section ("mysection"))) persistent_section2 = 2; /* { dg-warning "because it conflicts with attribute" } */
+const int __attribute__((persistent)) persistent_const = 3; /* { dg-warning "ignoring 'persistent' attribute set on const variable" } */
+int __attribute__((persistent)) persistent_init; /* { dg-warning "ignoring 'persistent' attribute set on uninitialized variable" } */
+void foo (void) { int __attribute__((persistent)) local_persistent = 4; } /* { dg-error "'persistent' attribute cannot be specified for local variables" } */
diff --git a/gcc/testsuite/c-c++-common/torture/attr-persistent-main.inc b/gcc/testsuite/c-c++-common/torture/attr-persistent-main.inc
new file mode 100644
index 0000000..a442141
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-persistent-main.inc
@@ -0,0 +1,58 @@
+/* This test checks that data marked with the "persistent" attribute is handled
+ correctly.
+ If data LMA != VMA (e.g. for simulating the copy of data from ROM to RAM),
+ then var_init will always be re-initialized to 2 and this test will loop
+ forever, so it must be skipped for those targets. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void _start (void) __attribute__ ((noreturn));
+#ifdef __cplusplus
+}
+#endif
+
+int var_common;
+int var_zero = 0;
+int var_one = 1;
+int __attribute__((persistent)) var_persistent = 2;
+int var_init = 2;
+
+int
+main (void)
+{
+ /* Make sure that the C startup code has correctly initialized the ordinary variables. */
+ if (var_common != 0)
+ __builtin_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 || var_persistent != 2)
+ __builtin_abort ();
+
+ switch (var_init)
+ {
+ case 2:
+ /* First time through - change all the values. */
+ var_common = var_zero = var_one = var_persistent = var_init = 3;
+ break;
+
+ case 3:
+ /* Second time through - make sure that var_persistent has not been reset. */
+ if (var_persistent != 3)
+ __builtin_abort ();
+ __builtin_exit (0);
+
+ default:
+ /* Any other value for var_init is an error. */
+ __builtin_abort ();
+ }
+
+ /* Simulate a processor reset by calling the C startup code. */
+ _start ();
+
+ /* Should never reach here. */
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 43ac526..ff6bc5f 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -380,6 +380,18 @@ proc check_effective_target_noinit { } {
return 0
}
+# The "persistent" attribute is only supported by some targets.
+# This proc returns 1 if it's supported, 0 if it's not.
+
+proc check_effective_target_persistent { } {
+ if { [istarget arm*-*-eabi]
+ || [istarget msp430-*-*] } {
+ return 1
+ }
+
+ return 0
+}
+
###############################
# proc check_visibility_available { what_kind }
###############################
diff --git a/gcc/tree.h b/gcc/tree.h
index 664449a..078919b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2669,6 +2669,13 @@ extern tree vector_element_bits_tree (const_tree);
(DECL_P (DECL) \
&& (lookup_attribute ("noinit", DECL_ATTRIBUTES (DECL)) != NULL_TREE))
+/* Nonzero for a decl that is decorated with the "persistent" attribute.
+ decls with this attribute are placed into the ".persistent" section, so they
+ are not initialized by the target's startup code. */
+#define DECL_PERSISTENT_P(DECL) \
+ (DECL_P (DECL) \
+ && (lookup_attribute ("persistent", DECL_ATTRIBUTES (DECL)) != NULL_TREE))
+
/* For function local variables of COMPLEX and VECTOR types,
indicates that the variable is not aliased, and that all
modifications to the variable have been adjusted so that
diff --git a/gcc/varasm.c b/gcc/varasm.c
index da7d0d7..b92da26 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -1057,7 +1057,11 @@ bss_initializer_p (const_tree decl, bool named)
|| (DECL_INITIAL (decl) == error_mark_node
&& !in_lto_p)
|| (flag_zero_initialized_in_bss
- && initializer_zerop (DECL_INITIAL (decl)))));
+ && initializer_zerop (DECL_INITIAL (decl))
+ /* A decl with the "persistent" attribute applied and
+ explicitly initialized to 0 should not be treated as a BSS
+ variable. */
+ && !DECL_PERSISTENT_P (decl))));
}
/* Compute the alignment of variable specified by DECL.
@@ -6680,6 +6684,9 @@ default_section_type_flags (tree decl, const char *name, int reloc)
if (strcmp (name, ".noinit") == 0)
flags |= SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
+ if (strcmp (name, ".persistent") == 0)
+ flags |= SECTION_WRITE | SECTION_NOTYPE;
+
/* Various sections have special ELF types that the assembler will
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
@@ -7023,6 +7030,11 @@ default_elf_select_section (tree decl, int reloc,
sname = ".sdata2";
break;
case SECCAT_DATA:
+ if (DECL_P (decl) && DECL_PERSISTENT_P (decl))
+ {
+ sname = ".persistent";
+ break;
+ }
return data_section;
case SECCAT_DATA_REL:
sname = ".data.rel";
@@ -7093,6 +7105,11 @@ default_unique_section (tree decl, int reloc)
break;
case SECCAT_DATA:
prefix = one_only ? ".d" : ".data";
+ if (DECL_P (decl) && DECL_PERSISTENT_P (decl))
+ {
+ prefix = one_only ? ".p" : ".persistent";
+ break;
+ }
break;
case SECCAT_DATA_REL:
prefix = one_only ? ".d.rel" : ".data.rel";