[PATCH] Add -fgnu-retain/-fno-gnu-retain

H.J. Lu hjl.tools@gmail.com
Mon Feb 15 22:35:07 GMT 2021


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 -fgnu-retain to disable SHF_GNU_RETAIN for Linux kernel build with
-fno-gnu-retain.

gcc/

	PR target/99113
	* common.opt: Add -fgnu-retain.
	* toplev.c (process_options): Update flag_gnu_retain from
	SUPPORTS_SHF_GNU_RETAIN.
	* varasm.c (get_section): Replace SUPPORTS_SHF_GNU_RETAIN with
	flag_gnu_retain.
	(resolve_unique_section): Likewise.
	(get_variable_section): Likewise.
	(switch_to_section): Likewise.
	* doc/invoke.texi: Document -fgnu-retain/-fno-gnu-retain.

gcc/testsuite/

	* c-c++-common/pr99113.c: New test.
---
 gcc/common.opt                       | 4 ++++
 gcc/doc/invoke.texi                  | 8 ++++++++
 gcc/testsuite/c-c++-common/pr99113.c | 7 +++++++
 gcc/toplev.c                         | 9 +++++++++
 gcc/varasm.c                         | 8 ++++----
 5 files changed, 32 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr99113.c

diff --git a/gcc/common.opt b/gcc/common.opt
index c75dd36843e..912e879e49d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1666,6 +1666,10 @@ floop-unroll-and-jam
 Common Var(flag_unroll_jam) Optimization
 Perform unroll-and-jam on loops.
 
+fgnu-retain
+Common Var(flag_gnu_retain) Init(-1)
+Use SHF_GNU_RETAIN if supported by the assembler and the linker.
+
 fgnu-tm
 Common Var(flag_tm)
 Enable support for GNU transactional memory.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e8baa545eee..20962a8749e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -16168,6 +16168,14 @@ DSOs; if your program relies on reinitialization of a DSO via
 @code{dlclose} and @code{dlopen}, you can use
 @option{-fno-gnu-unique}.
 
+@item -fno-gnu-retain
+@opindex fno-gnu-retain
+@opindex fgnu-retain
+On systems with recent GNU assembler and linker, the compiler places
+preserved symbols in separate SHF_GNU_RETAIN sections.  If your program,
+like Linux kernel, doesn't work with such symbol placement, you can use
+@option{-fno-gnu-retain} to disable SHF_GNU_RETAIN sections.
+
 @item -fpcc-struct-return
 @opindex fpcc-struct-return
 Return ``short'' @code{struct} and @code{union} values in memory like
diff --git a/gcc/testsuite/c-c++-common/pr99113.c b/gcc/testsuite/c-c++-common/pr99113.c
new file mode 100644
index 00000000000..d3c830247a2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr99113.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2 -fno-gnu-retain " } */
+
+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/toplev.c b/gcc/toplev.c
index d8cc254adef..a1b18f5338c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1761,6 +1761,15 @@ process_options (void)
   if (flag_large_source_files)
     line_table->default_range_bits = 0;
 
+  if (flag_gnu_retain == -1)
+    flag_gnu_retain = SUPPORTS_SHF_GNU_RETAIN;
+  else if (flag_gnu_retain > 0 && !SUPPORTS_SHF_GNU_RETAIN)
+    {
+      warning_at (UNKNOWN_LOCATION, 0, "%qs is not supported for this target",
+		  "-fgnu-retain");
+      flag_gnu_retain = 0;
+    }
+
   /* Please don't change global_options after this point, those changes won't
      be reflected in optimization_{default,current}_node.  */
 }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 29478ab0d8d..4e0e30abee5 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -297,7 +297,7 @@ 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
+  if (flag_gnu_retain
       && decl != nullptr
       && DECL_P (decl)
       && DECL_PRESERVE_P (decl))
@@ -487,7 +487,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))
+	  || (flag_gnu_retain && DECL_PRESERVE_P (decl))
 	  || DECL_COMDAT_GROUP (decl)))
     {
       targetm.asm_out.unique_section (decl, reloc);
@@ -1227,7 +1227,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)))
+      && !(flag_gnu_retain && DECL_PRESERVE_P (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,7 +7761,7 @@ switch_to_section (section *new_section, tree decl)
 {
   if (in_section == new_section)
     {
-      if (SUPPORTS_SHF_GNU_RETAIN
+      if (flag_gnu_retain
 	  && (new_section->common.flags & SECTION_NAMED)
 	  && decl != nullptr
 	  && DECL_P (decl)
-- 
2.29.2



More information about the Gcc-patches mailing list