In assemly code, the section flag 'R' sets the SHF_GNU_RETAIN flag to
indicate that the section must be preserved by the linker.

Add SECTION_RETAIN to indicate a section should be retained by the linker
and set SECTION_RETAIN on section for the preserved symbol if assembler
supports SHF_GNU_RETAIN.  All retained symbols are placed in separate
sections with

        .section .data.rel.local.preserved_symbol,"awR"
preserved_symbol:
...
        .section .data.rel.local,"aw"
not_preserved_symbol:
...

to avoid

        .section .data.rel.local,"awR"
preserved_symbol:
...
not_preserved_symbol:
...

which places not_preserved_symbol definition in the SHF_GNU_RETAIN
section.

gcc/

2020-11-XX  H.J. Lu  <hjl.to...@gmail.com>

        * configure.ac (HAVE_GAS_SHF_GNU_RETAIN): New.  Define 1 if
        the assembler supports marking sections with SHF_GNU_RETAIN flag.
        * output.h (SECTION_RETAIN): New.  Defined as 0x4000000.
        (SECTION_MACH_DEP): Changed from 0x4000000 to 0x8000000.
        (default_unique_section): Add a bool argument.
        * varasm.c (get_section): Set SECTION_RETAIN for the preserved
        symbol with HAVE_GAS_SHF_GNU_RETAIN.
        (resolve_unique_section): Used named section for the preserved
        symbol if assembler supports SHF_GNU_RETAIN.
        (get_variable_section): Handle the preserved common symbol with
        HAVE_GAS_SHF_GNU_RETAIN.
        (default_elf_asm_named_section): Require the full declaration and
        use the 'R' flag for SECTION_RETAIN.
        * config.in: Regenerated.
        * configure: Likewise.

gcc/testsuite/

2020-11-XX  H.J. Lu  <hjl.to...@gmail.com>
            Jozef Lawrynowicz  <joze...@mittosystems.com>

        * c-c++-common/attr-used.c: Check the 'R' flag.
        * c-c++-common/attr-used-2.c: Likewise.
        * c-c++-common/attr-used-3.c: New test.
        * c-c++-common/attr-used-4.c: Likewise.
        * gcc.c-torture/compile/attr-used-retain-1.c: Likewise.
        * gcc.c-torture/compile/attr-used-retain-2.c: Likewise.
        * lib/target-supports.exp
        (check_effective_target_R_flag_in_section): New proc.
---
 gcc/config.in                                 |  7 +++
 gcc/configure                                 | 51 +++++++++++++++++++
 gcc/configure.ac                              | 20 ++++++++
 gcc/output.h                                  |  6 ++-
 gcc/testsuite/c-c++-common/attr-used-2.c      |  1 +
 gcc/testsuite/c-c++-common/attr-used-3.c      |  7 +++
 gcc/testsuite/c-c++-common/attr-used-4.c      |  7 +++
 gcc/testsuite/c-c++-common/attr-used.c        |  1 +
 .../compile/attr-used-retain-1.c              | 32 ++++++++++++
 .../compile/attr-used-retain-2.c              | 15 ++++++
 gcc/testsuite/lib/target-supports.exp         | 40 +++++++++++++++
 gcc/varasm.c                                  | 17 +++++--
 12 files changed, 200 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/attr-used-3.c
 create mode 100644 gcc/testsuite/c-c++-common/attr-used-4.c
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c

diff --git a/gcc/config.in b/gcc/config.in
index b7c3107bfe3..23ae2f9bc1b 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1352,6 +1352,13 @@
 #endif
 
 
+/* Define 0/1 if your assembler supports marking sections with SHF_GNU_RETAIN
+   flag. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_SHF_GNU_RETAIN
+#endif
+
+
 /* Define 0/1 if your assembler supports marking sections with SHF_MERGE flag.
    */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/configure b/gcc/configure
index dbda4415a17..a925a6e5efb 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -24272,6 +24272,57 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+# Test if the assembler supports the section flag 'R' for specifying
+# section with SHF_GNU_RETAIN.
+case "${target}" in
+  # Solaris may use GNU assembler with Solairs ld.  Even if GNU
+  # assembler supports the section flag 'R', it doesn't mean that
+  # Solairs ld supports it.
+  *-*-solaris2*)
+    gcc_cv_as_shf_gnu_retain=no
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for section 
'R' flag" >&5
+$as_echo_n "checking assembler for section 'R' flag... " >&6; }
+if ${gcc_cv_as_shf_gnu_retain+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_shf_gnu_retain=no
+    if test $in_tree_gas = yes; then
+    if test $in_tree_gas_is_elf = yes \
+  && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 36 \) \* 1000 + 0`
+  then gcc_cv_as_shf_gnu_retain=yes
+fi
+  elif test x$gcc_cv_as != x; then
+    $as_echo '.section .foo,"awR",%progbits
+.byte 0' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags --fatal-warnings -o conftest.o 
conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+       gcc_cv_as_shf_gnu_retain=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_shf_gnu_retain" >&5
+$as_echo "$gcc_cv_as_shf_gnu_retain" >&6; }
+
+
+    ;;
+esac
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_GAS_SHF_GNU_RETAIN `if test $gcc_cv_as_shf_gnu_retain = yes; then 
echo 1; else echo 0; fi`
+_ACEOF
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for section 
merging support" >&5
 $as_echo_n "checking assembler for section merging support... " >&6; }
 if ${gcc_cv_as_shf_merge+:} false; then :
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 08f3034986e..9713b0abecc 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3256,6 +3256,26 @@ AC_DEFINE_UNQUOTED(HAVE_GAS_SECTION_EXCLUDE,
   [`if test $gcc_cv_as_section_exclude_e = yes || test 
$gcc_cv_as_section_exclude_hash = yes; then echo 1; else echo 0; fi`],
 [Define if your assembler supports specifying the exclude section flag.])
 
+# Test if the assembler supports the section flag 'R' for specifying
+# section with SHF_GNU_RETAIN.
+case "${target}" in
+  # Solaris may use GNU assembler with Solairs ld.  Even if GNU
+  # assembler supports the section flag 'R', it doesn't mean that
+  # Solairs ld supports it.
+  *-*-solaris2*)
+    gcc_cv_as_shf_gnu_retain=no
+    ;;
+  *)
+    gcc_GAS_CHECK_FEATURE([section 'R' flag], gcc_cv_as_shf_gnu_retain,
+      [elf,2,36,0], [--fatal-warnings],
+      [.section .foo,"awR",%progbits
+.byte 0])
+    ;;
+esac
+AC_DEFINE_UNQUOTED(HAVE_GAS_SHF_GNU_RETAIN,
+  [`if test $gcc_cv_as_shf_gnu_retain = yes; then echo 1; else echo 0; fi`],
+  [Define 0/1 if your assembler supports marking sections with SHF_GNU_RETAIN 
flag.])
+
 gcc_GAS_CHECK_FEATURE(section merging support, gcc_cv_as_shf_merge,
  [elf,2,12,0], [--fatal-warnings],
  [.section .rodata.str, "aMS", @progbits, 1])
diff --git a/gcc/output.h b/gcc/output.h
index 2f2f1697fd8..50c5f7b4a8b 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -381,7 +381,11 @@ extern void no_asm_to_stream (FILE *);
 #define SECTION_COMMON   0x800000      /* contains common data */
 #define SECTION_RELRO   0x1000000      /* data is readonly after relocation 
processing */
 #define SECTION_EXCLUDE  0x2000000     /* discarded by the linker */
-#define SECTION_MACH_DEP 0x4000000     /* subsequent bits reserved for target 
*/
+#define SECTION_RETAIN  0x4000000      /* retained by the linker.  */
+
+/* NB: The maximum SECTION_MACH_DEP is 0x10000000 since AVR needs 4 bits
+   in SECTION_MACH_DEP.  */
+#define SECTION_MACH_DEP 0x8000000     /* subsequent bits reserved for target 
*/
 
 /* This SECTION_STYLE is used for unnamed sections that we can switch
    to using a special assembler directive.  */
diff --git a/gcc/testsuite/c-c++-common/attr-used-2.c 
b/gcc/testsuite/c-c++-common/attr-used-2.c
index f78b94b53a9..eef2519643f 100644
--- a/gcc/testsuite/c-c++-common/attr-used-2.c
+++ b/gcc/testsuite/c-c++-common/attr-used-2.c
@@ -9,3 +9,4 @@ void foo()
 }
 
 /* { 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-used-3.c 
b/gcc/testsuite/c-c++-common/attr-used-3.c
new file mode 100644
index 00000000000..ca64197929c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-used-3.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2 -fcommon" } */
+
+static int xyzzy __attribute__((__used__)); 
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-used-4.c 
b/gcc/testsuite/c-c++-common/attr-used-4.c
new file mode 100644
index 00000000000..1cbc4c703e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-used-4.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2 -fcommon" } */
+
+int xyzzy __attribute__((__used__)); 
+
+/* { dg-final { scan-assembler "xyzzy" } } */
+/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
diff --git a/gcc/testsuite/c-c++-common/attr-used.c 
b/gcc/testsuite/c-c++-common/attr-used.c
index ba7705aaa77..2036533c959 100644
--- a/gcc/testsuite/c-c++-common/attr-used.c
+++ b/gcc/testsuite/c-c++-common/attr-used.c
@@ -11,3 +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 } 
} } */
diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c 
b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
new file mode 100644
index 00000000000..b7763af11e4
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
@@ -0,0 +1,32 @@
+/* { 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\"" } } */
+
+void __attribute__((used)) used_fn (void) { }
+void unused_fn (void) { }
+void __attribute__((hot,used)) used_hot_fn (void) { }
+void __attribute__((hot)) unused_hot_fn (void) { }
+void __attribute__((cold,used)) used_cold_fn (void) { }
+void __attribute__((cold)) unused_cold_fn (void) { }
+int __attribute__((used)) used_bss = 0;
+int __attribute__((used)) used_data = 1;
+const int __attribute__((used)) used_rodata = 2;
+int __attribute__((used)) used_comm;
+static int __attribute__((used)) 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 retained sections.  */
+void __attribute__((used)) used_fn2 (void) { }
+int __attribute__((used)) used_bss2 = 0;
+int __attribute__((used)) used_data2 = 1;
+const int __attribute__((used)) used_rodata2 = 2;
+int __attribute__((used)) used_comm2;
+static int __attribute__((used)) used_lcomm2;
diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c 
b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c
new file mode 100644
index 00000000000..e3b3cf184f8
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c
@@ -0,0 +1,15 @@
+/* { 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-options "-ffunction-sections -fdata-sections" } */
+
+#include "attr-used-retain-1.c"
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index ceee78c26a9..dbebaeb638f 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -10643,3 +10643,43 @@ proc check_effective_target_no_fsanitize_address {} {
     }
     return 0;
 }
+
+# Return 1 if this target supports 'R' flag in .section directive, 0
+# otherwise.  Cache the result.
+
+proc check_effective_target_R_flag_in_section { } {
+    global tool
+    global GCC_UNDER_TEST
+
+    # Need auto-host.h to check linker support.
+    if { ![file exists ../../auto-host.h ] } {
+       return 0
+    }
+
+    return [check_cached_effective_target R_flag_in_section {
+
+       set src pie[pid].c
+       set obj pie[pid].o
+
+       set f [open $src "w"]
+       puts $f "#include \"../../auto-host.h\""
+       puts $f "#if HAVE_GAS_SHF_GNU_RETAIN == 0"
+       puts $f "# error Assembler does not support 'R' flag in .section 
directive."
+       puts $f "#endif"
+       close $f
+
+       verbose "check_effective_target_R_flag_in_section compiling testfile 
$src" 2
+       set lines [${tool}_target_compile $src $obj assembly ""]
+
+       file delete $src
+       file delete $obj
+
+       if [string match "" $lines] then {
+           verbose "check_effective_target_R_flag_in_section testfile 
compilation passed" 2
+           return 1
+       } else {
+           verbose "check_effective_target_R_flag_in_section testfile 
compilation failed" 2
+           return 0
+       }
+    }]
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 435c7b348a5..c48ef9692ee 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -289,6 +289,10 @@ 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 HAVE_GAS_SHF_GNU_RETAIN
+  if (decl != nullptr && DECL_PRESERVE_P (decl))
+    flags |= SECTION_RETAIN;
+#endif
   if (*slot == NULL)
     {
       sect = ggc_alloc<section> ();
@@ -469,6 +473,9 @@ 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
+#if HAVE_GAS_SHF_GNU_RETAIN
+         || DECL_PRESERVE_P (decl)
+#endif
          || DECL_COMDAT_GROUP (decl)))
     {
       targetm.asm_out.unique_section (decl, reloc);
@@ -1170,7 +1177,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
   if (vnode)
     vnode->get_constructor ();
 
-  if (DECL_COMMON (decl))
+  if (DECL_COMMON (decl)
+      && !(HAVE_GAS_SHF_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
@@ -6704,9 +6712,10 @@ default_elf_asm_named_section (const char *name, 
unsigned int flags,
 
   /* If we have already declared this section, we can use an
      abbreviated form to switch back to it -- unless this section is
-     part of a COMDAT groups, in which case GAS requires the full
-     declaration every time.  */
+     part of a COMDAT groups or with SHF_GNU_RETAIN, in which case GAS
+     requires the full declaration every time.  */
   if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+      && !(flags & SECTION_RETAIN)
       && (flags & SECTION_DECLARED))
     {
       fprintf (asm_out_file, "\t.section\t%s\n", name);
@@ -6739,6 +6748,8 @@ default_elf_asm_named_section (const char *name, unsigned 
int flags,
        *f++ = TLS_SECTION_ASM_FLAG;
       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
        *f++ = 'G';
+      if (flags & SECTION_RETAIN)
+       *f++ = 'R';
 #ifdef MACH_DEP_SECTION_ASM_FLAG
       if (flags & SECTION_MACH_DEP)
        *f++ = MACH_DEP_SECTION_ASM_FLAG;
-- 
2.28.0

Reply via email to