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:
parent
670f5095e4
commit
6fbec038f7
@ -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
51
gcc/configure
vendored
@ -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 :
|
||||
|
@ -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])
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -9,3 +9,4 @@ void foo()
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */
|
||||
|
7
gcc/testsuite/c-c++-common/attr-used-3.c
Normal file
7
gcc/testsuite/c-c++-common/attr-used-3.c
Normal 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 } } } */
|
7
gcc/testsuite/c-c++-common/attr-used-4.c
Normal file
7
gcc/testsuite/c-c++-common/attr-used-4.c
Normal 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 } } } */
|
@ -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 } } } */
|
||||
|
35
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
Normal file
35
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c
Normal 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;
|
16
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c
Normal file
16
gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c
Normal 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"
|
@ -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
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
15
gcc/varasm.c
15
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<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;
|
||||
|
Loading…
Reference in New Issue
Block a user