Add retain attribute to place symbols in SHF_GNU_RETAIN section
authorH.J. Lu <hjl.tools@gmail.com>
Mon, 15 Feb 2021 19:31:12 +0000 (11:31 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 18 Feb 2021 21:27:38 +0000 (13:27 -0800)
When building Linux kernel, ld in bninutils 2.36 with GCC 11 generates
thousands of

ld: warning: orphan section `.data.event_initcall_finish' from `init/main.o' being placed in section `.data.event_initcall_finish'
ld: warning: orphan section `.data.event_initcall_start' from `init/main.o' being placed in section `.data.event_initcall_start'
ld: warning: orphan section `.data.event_initcall_level' from `init/main.o' being placed in section `.data.event_initcall_level'

Since these sections are marked with SHF_GNU_RETAIN, they are placed in
separate sections.  They become orphan sections since they aren't expected
in the Linux kernel linker script. But orphan sections normally don't work
well with the Linux kernel linker script and the resulting kernel crashed.

Add the "retain" attribute to place symbols in separate SHF_GNU_RETAIN
sections.  Issue a warning if the configured assembler/linker doesn't
support SHF_GNU_RETAIN.

gcc/

PR target/99113
* varasm.c (get_section): Replace SUPPORTS_SHF_GNU_RETAIN with
looking up the retain attribute.
(resolve_unique_section): Likewise.
(get_variable_section): Likewise.
(switch_to_section): Likewise.  Warn when a symbol without the
retain attribute and a symbol with the retain attribute are
placed in the section with the same name, instead of the used
attribute.
* doc/extend.texi: Document the "retain" attribute.

gcc/c-family/

PR target/99113
* c-attribs.c (c_common_attribute_table): Add the "retain"
attribute.
(handle_retain_attribute): New function.

gcc/testsuite/

PR target/99113
* c-c++-common/attr-retain-1.c: New test.
* c-c++-common/attr-retain-2.c: Likewise.
* c-c++-common/attr-retain-3.c: Likewise.
* c-c++-common/attr-retain-4.c: Likewise.
* c-c++-common/attr-retain-5.c: Likewise.
* c-c++-common/attr-retain-6.c: Likewise.
* c-c++-common/attr-retain-7.c: Likewise.
* c-c++-common/attr-retain-8.c: Likewise.
* c-c++-common/attr-retain-9.c: Likewise.
* c-c++-common/pr99113.c: Likewise.
* gcc.c-torture/compile/attr-retain-1.c: Likewise.
* gcc.c-torture/compile/attr-retain-2.c: Likewise.
* c-c++-common/attr-used.c: Don't expect SHF_GNU_RETAIN section.
* c-c++-common/attr-used-2.c: Likewise.
* c-c++-common/attr-used-3.c: Likewise.
* c-c++-common/attr-used-4.c: Likewise.
* c-c++-common/attr-used-9.c: Likewise.
* gcc.c-torture/compile/attr-used-retain-1.c: Likewise.
* gcc.c-torture/compile/attr-used-retain-2.c: Likewise.
* c-c++-common/attr-used-5.c: Don't expect warning for the used
attribute nor SHF_GNU_RETAIN section.
* c-c++-common/attr-used-6.c: Likewise.
* c-c++-common/attr-used-7.c: Likewise.
* c-c++-common/attr-used-8.c: Likewise.

26 files changed:
gcc/c-family/c-attribs.c
gcc/doc/extend.texi
gcc/testsuite/c-c++-common/attr-retain-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-5.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-6.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-7.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-8.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-retain-9.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/attr-used-2.c
gcc/testsuite/c-c++-common/attr-used-3.c
gcc/testsuite/c-c++-common/attr-used-4.c
gcc/testsuite/c-c++-common/attr-used-5.c
gcc/testsuite/c-c++-common/attr-used-6.c
gcc/testsuite/c-c++-common/attr-used-7.c
gcc/testsuite/c-c++-common/attr-used-8.c
gcc/testsuite/c-c++-common/attr-used-9.c
gcc/testsuite/c-c++-common/attr-used.c
gcc/testsuite/c-c++-common/pr99113.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c
gcc/varasm.c

index 0cb51fddfaaaaaf607984d74271917e2d186c46c..ae31e4c1f6fa9450377e94e05f8dbe7e4c2b2238 100644 (file)
@@ -163,6 +163,7 @@ static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *);
 static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *);
 static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int,
                                                    bool *);
+static tree handle_retain_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)      \
@@ -328,6 +329,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_used_attribute, NULL },
   { "unused",                 0, 0, false, false, false, false,
                              handle_unused_attribute, NULL },
+  { "retain",                 0, 0, true,  false, false, false,
+                             handle_retain_attribute, NULL },
   { "externally_visible",     0, 0, true,  false, false, false,
                              handle_externally_visible_attribute, NULL },
   { "no_reorder",            0, 0, true, false, false, false,
@@ -1564,6 +1567,28 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle a "retain" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+                        int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if (SUPPORTS_SHF_GNU_RETAIN
+      && (TREE_CODE (node) == FUNCTION_DECL
+         || (VAR_P (node) && TREE_STATIC (node))))
+    ;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "externally_visible" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index 6eb1d327e97dc94b0d8c4787e3eb955f3efe4ab6..8bbb93724a93b42c3f13a164f11b4f7e4007d33a 100644 (file)
@@ -3913,8 +3913,10 @@ When applied to a member function of a C++ class template, the
 attribute also means that the function is instantiated if the
 class itself is instantiated.
 
+@item retain
+@cindex @code{retain} function attribute
 For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
-will also save the function from linker garbage collection.  To support
+will save the function from linker garbage collection.  To support
 this behavior, functions that have not been placed in specific sections
 (e.g. by the @code{section} attribute, or the @code{-ffunction-sections}
 option), will be placed in new, unique sections.
@@ -7504,8 +7506,10 @@ When applied to a static data member of a C++ class template, the
 attribute also means that the member is instantiated if the
 class itself is instantiated.
 
+@item retain
+@cindex @code{retain} variable attribute
 For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
-will also save the variable from linker garbage collection.  To support
+will save the variable from linker garbage collection.  To support
 this behavior, variables that have not been placed in specific sections
 (e.g. by the @code{section} attribute, or the @code{-fdata-sections} option),
 will be placed in new, unique sections.
diff --git a/gcc/testsuite/c-c++-common/attr-retain-1.c b/gcc/testsuite/c-c++-common/attr-retain-1.c
new file mode 100644 (file)
index 0000000..d060fbf
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-options "-O3" } */
+
+static void function_declaration_before(void)
+  __attribute__((__used__, __retain__));
+
+static void function_declaration_before(void) {}
+
+static void function_declaration_after(void) {}
+
+static void function_declaration_after(void)
+  __attribute__((__used__, __retain__));
+
+/* { dg-final { scan-assembler "function_declaration_before" } } */
+/* { dg-final { scan-assembler "function_declaration_after" } } */
+/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-2.c b/gcc/testsuite/c-c++-common/attr-retain-2.c
new file mode 100644 (file)
index 0000000..6baba84
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-options "-Wall -O2" } */
+
+static int xyzzy __attribute__((__used__, __retain__)) = 1; 
+
+void foo()
+{
+  int x __attribute__((__retain__)); /* { dg-warning "attribute ignored|unused variable" } */
+}
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-3.c b/gcc/testsuite/c-c++-common/attr-retain-3.c
new file mode 100644 (file)
index 0000000..a4077a1
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-options "-Wall -O2 -fcommon" } */
+
+static int xyzzy __attribute__((__used__, __retain__)); 
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-4.c b/gcc/testsuite/c-c++-common/attr-retain-4.c
new file mode 100644 (file)
index 0000000..590e47c
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-options "-Wall -O2 -fcommon" } */
+
+int xyzzy __attribute__((__used__, __retain__)); 
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-5.c b/gcc/testsuite/c-c++-common/attr-retain-5.c
new file mode 100644 (file)
index 0000000..669fa90
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+  struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
+{
+  if (!free_slotinfo (&(*elemp)->next))
+    return 0;
+  return 1;
+}
+
+__attribute__ ((used, retain, section ("__libc_freeres_fn")))
+static void free_mem (void)
+{
+  free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-6.c b/gcc/testsuite/c-c++-common/attr-retain-6.c
new file mode 100644 (file)
index 0000000..1cf03a7
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+  struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((used, retain, section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+  if (!free_slotinfo (&(*elemp)->next))
+    return 0;
+  return 1;
+}
+
+__attribute__ ((section ("__libc_freeres_fn")))
+void free_mem (void)
+/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
+{
+  free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-7.c b/gcc/testsuite/c-c++-common/attr-retain-7.c
new file mode 100644 (file)
index 0000000..08f52fc
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
+/* { dg-options "-Wall -O2" } */
+
+int __attribute__((used,retain,section(".data.foo"))) foo2 = 2;
+int __attribute__((section(".data.foo"))) foo1 = 1;
+/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
+
+/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-8.c b/gcc/testsuite/c-c++-common/attr-retain-8.c
new file mode 100644 (file)
index 0000000..2dbec9e
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
+/* { dg-options "-Wall -O2" } */
+
+int __attribute__((section(".data.foo"))) foo1 = 1;
+/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
+int __attribute__((used,retain,section(".data.foo"))) foo2 = 2;
+
+/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-retain-9.c b/gcc/testsuite/c-c++-common/attr-retain-9.c
new file mode 100644 (file)
index 0000000..f26e25d
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+  struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((used, retain, section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+  if (!free_slotinfo (&(*elemp)->next))
+    return 0;
+  return 1;
+}
+
+__attribute__ ((section ("__libc_freeres_fn")))
+static void free_mem (void)
+/* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */
+{
+  free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler-not "__libc_freeres_fn\n" } } */
+/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
index eef2519643fbae016948271c5b177a2bf74f3d81..5849747d1e4b02d111b7f49215fe749154c12a95 100644 (file)
@@ -9,4 +9,4 @@ void foo()
 }
 
 /* { dg-final { scan-assembler "xyzzy" } } */
-/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */
index ca64197929c7f59116efb81156eb14008a4316fc..5a6ea991dc4b95c6a8f4b042797e39a64692995d 100644 (file)
@@ -4,4 +4,4 @@
 static int xyzzy __attribute__((__used__)); 
 
 /* { dg-final { scan-assembler "xyzzy" } } */
-/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */
index 1cbc4c703e9e5a598f2c212381dfb21285acd475..40c2c659d3c70dbc12c8be173bf097db700e0cf1 100644 (file)
@@ -4,4 +4,4 @@
 int xyzzy __attribute__((__used__)); 
 
 /* { dg-final { scan-assembler "xyzzy" } } */
-/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */
index 5b4924160fd7c857b5e6de0430ea58023f9791d6..448e19f6f0eabdf7d84218f3f138e6f65a084ffb 100644 (file)
@@ -11,7 +11,6 @@ extern struct dtv_slotinfo_list *list;
 
 static int __attribute__ ((section ("__libc_freeres_fn")))
 free_slotinfo (struct dtv_slotinfo_list **elemp)
-/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
 {
   if (!free_slotinfo (&(*elemp)->next))
     return 0;
@@ -25,4 +24,4 @@ static void free_mem (void)
 }
 
 /* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
-/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
index 3cf288dd28fa004d17c9fa8a92e35e3271729c00..b9974e2a4f29273b80709c00b9dcda873bea27da 100644 (file)
@@ -19,10 +19,9 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
 
 __attribute__ ((section ("__libc_freeres_fn")))
 void free_mem (void)
-/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
 {
   free_slotinfo (&list);
 }
 
 /* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
-/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
index 1721a8afc4e9df740a8dfe7762509f5a18ae6ce1..9c9862fcafd98c41475ab80a58d70487d833fd86 100644 (file)
@@ -4,7 +4,6 @@
 
 int __attribute__((used,section(".data.foo"))) foo2 = 2;
 int __attribute__((section(".data.foo"))) foo1 = 1;
-/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
 
 /* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
-/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */
index 20662cadf7019361faaeb32af79eb094e97cb67d..c907ab116416bc10ed90431f4f42933da3e7c2c6 100644 (file)
@@ -3,8 +3,7 @@
 /* { dg-options "-Wall -O2" } */
 
 int __attribute__((section(".data.foo"))) foo1 = 1;
-/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
 int __attribute__((used,section(".data.foo"))) foo2 = 2;
 
 /* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
-/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */
index 5847b0550ced9c8be976b162aec3c68f7e59a7d6..049c0beb1eee2a601164551b4f3193c6b97dbec7 100644 (file)
@@ -25,5 +25,5 @@ static void free_mem (void)
 }
 
 /* { dg-final { scan-assembler-not "__libc_freeres_fn\n" } } */
-/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
-/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
index 2036533c959beb3fe14b5b827aa231c6fe9dba68..96c6d67434612c612d6f473c42a9d229f6a5e570 100644 (file)
@@ -11,4 +11,4 @@ static void function_declaration_after(void) __attribute__((__used__));
 
 /* { dg-final { scan-assembler "function_declaration_before" } } */
 /* { dg-final { scan-assembler "function_declaration_after" } } */
-/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler-not "\.text.*,\"axR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/pr99113.c b/gcc/testsuite/c-c++-common/pr99113.c
new file mode 100644 (file)
index 0000000..0181401
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+static int xyzzy __attribute__((__used__)) = 1; 
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c b/gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c
new file mode 100644 (file)
index 0000000..6cab155
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */
+/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */
+/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */
+/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */
+/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
+
+void __attribute__((used,retain)) used_fn (void) { }
+void unused_fn (void) { }
+void __attribute__((hot,used,retain)) used_hot_fn (void) { }
+void __attribute__((hot)) unused_hot_fn (void) { }
+void __attribute__((cold,used,retain)) used_cold_fn (void) { }
+void __attribute__((cold)) unused_cold_fn (void) { }
+int __attribute__((used,retain)) used_bss = 0;
+int __attribute__((used,retain)) used_data = 1;
+const int __attribute__((used,retain)) used_rodata = 2;
+int __attribute__((used,retain)) used_comm;
+static int __attribute__((used,retain)) used_lcomm;
+
+int unused_bss = 0;
+int unused_data = 1;
+const int unused_rodata = 2;
+int unused_comm;
+static int unused_lcomm;
+
+/* Test switching back to the used,retained sections.  */
+void __attribute__((used,retain)) used_fn2 (void) { }
+int __attribute__((used,retain)) used_bss2 = 0;
+int __attribute__((used,retain)) used_data2 = 1;
+const int __attribute__((used,retain)) used_rodata2 = 2;
+int __attribute__((used,retain)) used_comm2;
+static int __attribute__((used,retain)) used_lcomm2;
+
+int __attribute__((used,retain,section(".data.used_foo_sec"))) used_foo = 2;
diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c b/gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c
new file mode 100644 (file)
index 0000000..0208ffe
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile { target R_flag_in_section } } */
+/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */
+/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */
+/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */
+/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */
+/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */
+/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */
+/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */
+/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */
+/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
+/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
+/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
+/* { dg-options "-ffunction-sections -fdata-sections" } */
+
+#include "attr-retain-1.c"
index 5f6cbca6e33857fbf331b6c6233524addbd59bb1..bf5ca48c3160d7956cfa51db65a31a783633a923 100644 (file)
@@ -1,10 +1,10 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target R_flag_in_section } */
-/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */
-/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */
-/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */
-/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */
-/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".text.*,\"axR\"" } } */
+/* { dg-final { scan-assembler-not ".bss.*,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".data.*,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".rodata.*,\"aR\"" } } */
+/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */
 
 void __attribute__((used)) used_fn (void) { }
 void unused_fn (void) { }
index be5f3917ac80cf7020440fa87c66f11c47a4a618..7858e62c15417a0894e04e2bf5cff77efd2e2d81 100644 (file)
@@ -1,16 +1,16 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target R_flag_in_section } */
-/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */
-/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */
-/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */
-/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */
-/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */
-/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */
-/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */
-/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */
-/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
-/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
-/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".text.used_fn,\"axR\"" } } */
+/* { dg-final { scan-assembler-not ".text.used_fn2,\"axR\"" } } */
+/* { dg-final { scan-assembler-not ".bss.used_bss,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".bss.used_bss2,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".data.used_data,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".data.used_data2,\"awR\"" } } */
+/* { dg-final { scan-assembler-not ".rodata.used_rodata,\"aR\"" } } */
+/* { dg-final { scan-assembler-not ".rodata.used_rodata2,\"aR\"" } } */
+/* { dg-final { scan-assembler-not ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
+/* { dg-final { scan-assembler-not ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
+/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */
 /* { dg-options "-ffunction-sections -fdata-sections" } */
 
 #include "attr-used-retain-1.c"
index 29478ab0d8d563a420c49e056220a8e0a3873731..811212244a552e9bab9e1203ea9273dbab6e3725 100644 (file)
@@ -297,10 +297,9 @@ get_section (const char *name, unsigned int flags, tree decl,
   slot = section_htab->find_slot_with_hash (name, htab_hash_string (name),
                                            INSERT);
   flags |= SECTION_NAMED;
-  if (SUPPORTS_SHF_GNU_RETAIN
-      && decl != nullptr
+  if (decl != nullptr
       && DECL_P (decl)
-      && DECL_PRESERVE_P (decl))
+      && lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
     flags |= SECTION_RETAIN;
   if (*slot == NULL)
     {
@@ -487,7 +486,7 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
   if (DECL_SECTION_NAME (decl) == NULL
       && targetm_common.have_named_sections
       && (flag_function_or_data_sections
-         || (SUPPORTS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl))
+         || lookup_attribute ("retain", DECL_ATTRIBUTES (decl))
          || DECL_COMDAT_GROUP (decl)))
     {
       targetm.asm_out.unique_section (decl, reloc);
@@ -1227,7 +1226,7 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
     vnode->get_constructor ();
 
   if (DECL_COMMON (decl)
-      && !(SUPPORTS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl)))
+      && !lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
     {
       /* If the decl has been given an explicit section name, or it resides
         in a non-generic address space, then it isn't common, and shouldn't
@@ -7761,18 +7760,19 @@ switch_to_section (section *new_section, tree decl)
 {
   if (in_section == new_section)
     {
-      if (SUPPORTS_SHF_GNU_RETAIN
-         && (new_section->common.flags & SECTION_NAMED)
+      bool retain_p;
+      if ((new_section->common.flags & SECTION_NAMED)
          && decl != nullptr
          && DECL_P (decl)
-         && (!!DECL_PRESERVE_P (decl)
+         && ((retain_p = !!lookup_attribute ("retain",
+                                             DECL_ATTRIBUTES (decl)))
              != !!(new_section->common.flags & SECTION_RETAIN)))
        {
          /* If the SECTION_RETAIN bit doesn't match, switch to a new
             section.  */
          tree used_decl, no_used_decl;
 
-         if (DECL_PRESERVE_P (decl))
+         if (retain_p)
            {
              new_section->common.flags |= SECTION_RETAIN;
              used_decl = decl;
@@ -7786,8 +7786,8 @@ switch_to_section (section *new_section, tree decl)
              no_used_decl = decl;
            }
          warning (OPT_Wattributes,
-                  "%+qD without %<used%> attribute and %qD with "
-                  "%<used%> attribute are placed in a section with "
+                  "%+qD without %<retain%> attribute and %qD with "
+                  "%<retain%> attribute are placed in a section with "
                   "the same name", no_used_decl, used_decl);
          inform (DECL_SOURCE_LOCATION (used_decl),
                  "%qD was declared here", used_decl);