diff --git a/gcc/config.in b/gcc/config.in index cc6276d0df0..b6e041d311e 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1386,6 +1386,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 5206f0d93b2..747822208f2 100755 --- a/gcc/configure +++ b/gcc/configure @@ -24430,6 +24430,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 ded124cb07f..478d0d6f238 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3330,6 +3330,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/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 4f7af2074fe..55538c3586b 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -2462,6 +2462,9 @@ Target supports wide characters. @subsubsection Other attributes @table @code +@item R_flag_in_section +Target supports the 'R' flag in .section directive in assembly inputs. + @item automatic_stack_alignment Target supports automatic stack alignment. diff --git a/gcc/output.h b/gcc/output.h index b44c1bd6fc7..729c52099e6 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..5f6cbca6e33 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c @@ -0,0 +1,35 @@ +/* { 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\"" } } */ + +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; + +int __attribute__((used,section(".data.used_foo_sec"))) used_foo = 2; 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..be5f3917ac8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c @@ -0,0 +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-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 ff6bc5f4b92..9d0a25d77e5 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -10662,3 +10662,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 b92da26fb82..6c13f528f7b 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 + && decl != nullptr + && DECL_PRESERVE_P (decl)) + flags |= SECTION_RETAIN; if (*slot == NULL) { sect = ggc_alloc
(); @@ -469,6 +473,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 + || (HAVE_GAS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl)) || DECL_COMDAT_GROUP (decl))) { targetm.asm_out.unique_section (decl, reloc); @@ -1207,7 +1212,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 @@ -6745,9 +6751,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); @@ -6780,6 +6787,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;