Use SHF_GNU_RETAIN to preserve symbol definitions

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-12-01  H.J. Lu  <hjl.tools@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.
	* doc/sourcebuild.texi: Document R_flag_in_section.

gcc/testsuite/

2020-12-01  H.J. Lu  <hjl.tools@gmail.com>
	    Jozef Lawrynowicz  <jozef.l@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.
This commit is contained in:
H.J. Lu 2020-02-03 11:55:43 -08:00
parent 670f5095e4
commit 6fbec038f7
13 changed files with 205 additions and 4 deletions

View File

@ -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

51
gcc/configure vendored
View File

@ -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 :

View File

@ -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])

View File

@ -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.

View File

@ -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. */

View File

@ -9,3 +9,4 @@ void foo()
}
/* { dg-final { scan-assembler "xyzzy" } } */
/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */

View File

@ -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 } } } */

View File

@ -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 } } } */

View File

@ -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 } } } */

View File

@ -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;

View File

@ -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"

View File

@ -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
}
}]
}

View File

@ -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<section> ();
@ -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;