[PATCH v3] Set the retain attribute on _elf_set_element if CC supports [BZ #27492]
Fangrui Song
maskray@google.com
Mon Mar 29 23:24:40 GMT 2021
So that text_set_element/data_set_element/bss_set_element defined
variables will be retained by the linker.
Note: 'used' and 'retain' are orthogonal: 'used' makes sure the variable
will not be optimized out; 'retain' prevents section garbage collection
if the linker support SHF_GNU_RETAIN.
GNU ld 2.37 and LLD 13 will support -z start-stop-gc which allow C
identifier name sections to be GCed even if there are live
__start_/__stop_ references.
Without the change, there are some static linking problems, e.g.
_IO_cleanup (libio/genops.c) may be discarded by ld --gc-sections, so
stdout is not flushed on exit.
Note: GCC may warning ‘retain’ attribute ignored while __has_attribute(retain) is 1
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99587).
---
Changes in v1 -> v2:
* Define attribute_used_retain_section
Changes in v2 -> v3:
* Use attribute_used_retain instead attribute_used_retain_section
---
config.h.in | 3 +++
configure | 23 +++++++++++++++++++++++
configure.ac | 16 ++++++++++++++++
include/libc-symbols.h | 14 ++++++++++----
4 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/config.h.in b/config.h.in
index ca1547ae67..95af1ef229 100644
--- a/config.h.in
+++ b/config.h.in
@@ -187,6 +187,9 @@
/* Define if gcc supports attribute ifunc. */
#undef HAVE_GCC_IFUNC
+/* Define if gcc supports attribute retain. */
+#undef HAVE_GCC_RETAIN
+
/* Define if the linker defines __ehdr_start. */
#undef HAVE_EHDR_START
diff --git a/configure b/configure
index fcf43bf7de..6a6b8ac264 100755
--- a/configure
+++ b/configure
@@ -4105,6 +4105,29 @@ fi
$as_echo "$libc_cv_textrel_ifunc" >&6; }
+# Check if gcc supports attribute ifunc as it is used in libc_ifunc macro.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc attribute retain support" >&5
+$as_echo_n "checking for gcc attribute retain support... " >&6; }
+if ${libc_cv_gcc_retain+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.c <<EOF
+static int var __attribute__ ((used, retain, section ("__libc_atexit")));
+EOF
+libc_cv_gcc_retain=no
+if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&5 \
+ 2>&5 ; then
+ libc_cv_gcc_retain=yes
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_retain" >&5
+$as_echo "$libc_cv_gcc_retain" >&6; }
+if test $libc_cv_gcc_retain = yes; then
+ $as_echo "#define HAVE_GCC_RETAIN 1" >>confdefs.h
+
+fi
+
# Check if gcc warns about alias for function with incompatible types.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler warns about alias for function with incompatible types" >&5
$as_echo_n "checking if compiler warns about alias for function with incompatible types... " >&6; }
diff --git a/configure.ac b/configure.ac
index fce967f2c2..031b8c3fb3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -707,6 +707,22 @@ fi
rm -f conftest*])
AC_SUBST(libc_cv_textrel_ifunc)
+# Check if gcc supports attribute ifunc as it is used in libc_ifunc macro.
+AC_CACHE_CHECK([for gcc attribute retain support],
+ libc_cv_gcc_retain, [dnl
+cat > conftest.c <<EOF
+static int var __attribute__ ((used, retain, section ("__libc_atexit")));
+EOF
+libc_cv_gcc_retain=no
+if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&AS_MESSAGE_LOG_FD \
+ 2>&AS_MESSAGE_LOG_FD ; then
+ libc_cv_gcc_retain=yes
+fi
+rm -f conftest*])
+if test $libc_cv_gcc_retain = yes; then
+ AC_DEFINE(HAVE_GCC_RETAIN)
+fi
+
# Check if gcc warns about alias for function with incompatible types.
AC_CACHE_CHECK([if compiler warns about alias for function with incompatible types],
libc_cv_gcc_incompatible_alias, [dnl
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index 546fc26a7b..b311c90f0c 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -352,6 +352,12 @@ for linking")
*/
+#ifdef HAVE_GCC_RETAIN
+# define attribute_used_retain __attribute__ ((__used__, __retain__))
+#else
+# define attribute_used_retain __attribute__ ((__used__))
+#endif
+
/* Symbol set support macros. */
/* Make SYMBOL, which is in the text segment, an element of SET. */
@@ -367,12 +373,12 @@ for linking")
/* When building a shared library, make the set section writable,
because it will need to be relocated at run time anyway. */
# define _elf_set_element(set, symbol) \
- static const void *__elf_set_##set##_element_##symbol##__ \
- __attribute__ ((used, section (#set))) = &(symbol)
+ static const void *__elf_set_##set##_element_##symbol##__ \
+ attribute_used_retain __attribute__ ((section (#set))) = &(symbol)
#else
# define _elf_set_element(set, symbol) \
- static const void *const __elf_set_##set##_element_##symbol##__ \
- __attribute__ ((used, section (#set))) = &(symbol)
+ static const void *const __elf_set_##set##_element_##symbol##__ \
+ attribute_used_retain __attribute__ ((section (#set))) = &(symbol)
#endif
/* Define SET as a symbol set. This may be required (it is in a.out) to
--
2.31.0.291.g576ba9dcdaf-goog
More information about the Libc-alpha
mailing list