diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-02-03 11:55:43 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-12-01 16:42:50 -0800 |
commit | 6fbec038f7a7ddf29f074943611b53210d17c40c (patch) | |
tree | 17b1d7fb7010085b8d79deab1e4a07edf51ddf9b /gcc | |
parent | 670f5095e4aacc30099f6b73c1e67c06df76f36b (diff) | |
download | gcc-6fbec038f7a7ddf29f074943611b53210d17c40c.zip gcc-6fbec038f7a7ddf29f074943611b53210d17c40c.tar.gz gcc-6fbec038f7a7ddf29f074943611b53210d17c40c.tar.bz2 |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config.in | 7 | ||||
-rwxr-xr-x | gcc/configure | 51 | ||||
-rw-r--r-- | gcc/configure.ac | 20 | ||||
-rw-r--r-- | gcc/doc/sourcebuild.texi | 3 | ||||
-rw-r--r-- | gcc/output.h | 6 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-used-2.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-used-3.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-used-4.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-used.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c | 35 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/lib/target-supports.exp | 40 | ||||
-rw-r--r-- | gcc/varasm.c | 15 |
13 files changed, 205 insertions, 4 deletions
diff --git a/gcc/config.in b/gcc/config.in index cc6276d..b6e041d 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 5206f0d..7478222 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 ded124c..478d0d6 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 4f7af20..55538c3 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 b44c1bd..729c520 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 f78b94b..eef2519 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 0000000..ca64197 --- /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 0000000..1cbc4c7 --- /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 ba7705a..2036533 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 0000000..5f6cbca --- /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 0000000..be5f391 --- /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 ff6bc5f..9d0a25d 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 b92da26..6c13f52 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<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; |