mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
Set the retain attribute on _elf_set_element if CC supports [BZ #27492]
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). Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
parent
1a8605b6cd
commit
cd6ae7ea54
@ -187,6 +187,9 @@
|
||||
/* Define if gcc supports attribute ifunc. */
|
||||
#undef HAVE_GCC_IFUNC
|
||||
|
||||
/* Define if CC supports attribute retain. */
|
||||
#undef HAVE_GNU_RETAIN
|
||||
|
||||
/* Define if the linker defines __ehdr_start. */
|
||||
#undef HAVE_EHDR_START
|
||||
|
||||
|
59
configure
vendored
59
configure
vendored
@ -4105,6 +4105,31 @@ fi
|
||||
$as_echo "$libc_cv_textrel_ifunc" >&6; }
|
||||
|
||||
|
||||
# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU attribute retain support" >&5
|
||||
$as_echo_n "checking for GNU attribute retain support... " >&6; }
|
||||
if ${libc_cv_gnu_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_gnu_retain=no
|
||||
if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&5 \
|
||||
2>&5 ; then
|
||||
libc_cv_gnu_retain=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gnu_retain" >&5
|
||||
$as_echo "$libc_cv_gnu_retain" >&6; }
|
||||
if test $libc_cv_gnu_retain = yes; then
|
||||
$as_echo "#define HAVE_GNU_RETAIN 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
config_vars="$config_vars
|
||||
have-gnu-retain = $libc_cv_gnu_retain"
|
||||
|
||||
# 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; }
|
||||
@ -5871,6 +5896,40 @@ fi
|
||||
$as_echo "$libc_linker_feature" >&6; }
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z start-stop-gc" >&5
|
||||
$as_echo_n "checking for linker that supports -z start-stop-gc... " >&6; }
|
||||
libc_linker_feature=no
|
||||
if test x"$gnu_ld" = x"yes"; then
|
||||
libc_linker_check=`$LD -v --help 2>/dev/null | grep "\-z start-stop-gc"`
|
||||
if test -n "$libc_linker_check"; then
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,-z,start-stop-gc -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&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
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
fi
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_z_start_stop_gc=yes
|
||||
else
|
||||
libc_cv_z_start_stop_gc=no
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
$as_echo "$libc_linker_feature" >&6; }
|
||||
config_vars="$config_vars
|
||||
have-z-start-stop-gc = $libc_cv_z_start_stop_gc"
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-dynamic-linker" >&5
|
||||
$as_echo_n "checking for linker that supports --no-dynamic-linker... " >&6; }
|
||||
libc_linker_feature=no
|
||||
|
21
configure.ac
21
configure.ac
@ -707,6 +707,23 @@ fi
|
||||
rm -f conftest*])
|
||||
AC_SUBST(libc_cv_textrel_ifunc)
|
||||
|
||||
# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
|
||||
AC_CACHE_CHECK([for GNU attribute retain support],
|
||||
libc_cv_gnu_retain, [dnl
|
||||
cat > conftest.c <<EOF
|
||||
static int var __attribute__ ((used, retain, section ("__libc_atexit")));
|
||||
EOF
|
||||
libc_cv_gnu_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_gnu_retain=yes
|
||||
fi
|
||||
rm -f conftest*])
|
||||
if test $libc_cv_gnu_retain = yes; then
|
||||
AC_DEFINE(HAVE_GNU_RETAIN)
|
||||
fi
|
||||
LIBC_CONFIG_VAR([have-gnu-retain], [$libc_cv_gnu_retain])
|
||||
|
||||
# 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
|
||||
@ -1317,6 +1334,10 @@ LIBC_LINKER_FEATURE([-z execstack], [-Wl,-z,execstack],
|
||||
[libc_cv_z_execstack=yes], [libc_cv_z_execstack=no])
|
||||
AC_SUBST(libc_cv_z_execstack)
|
||||
|
||||
LIBC_LINKER_FEATURE([-z start-stop-gc], [-Wl,-z,start-stop-gc],
|
||||
[libc_cv_z_start_stop_gc=yes], [libc_cv_z_start_stop_gc=no])
|
||||
LIBC_CONFIG_VAR([have-z-start-stop-gc], [$libc_cv_z_start_stop_gc])
|
||||
|
||||
LIBC_LINKER_FEATURE([--no-dynamic-linker],
|
||||
[-Wl,--no-dynamic-linker],
|
||||
[libc_cv_no_dynamic_linker=yes],
|
||||
|
@ -352,6 +352,12 @@ for linking")
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GNU_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
|
||||
|
@ -195,6 +195,26 @@ ifeq (yes,$(build-shared))
|
||||
tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
|
||||
$(objpfx)tst-bz24228-mem.out
|
||||
endif
|
||||
|
||||
tests += tst-cleanup-default tst-cleanup-default-static
|
||||
tests-static += tst-cleanup-default-static
|
||||
tests-special += $(objpfx)tst-cleanup-default-cmp.out $(objpfx)tst-cleanup-default-static-cmp.out
|
||||
LDFLAGS-tst-cleanup-default = -Wl,--gc-sections
|
||||
LDFLAGS-tst-cleanup-default-static = -Wl,--gc-sections
|
||||
|
||||
ifeq ($(have-gnu-retain)$(have-z-start-stop-gc),yesyes)
|
||||
tests += tst-cleanup-start-stop-gc tst-cleanup-start-stop-gc-static \
|
||||
tst-cleanup-nostart-stop-gc tst-cleanup-nostart-stop-gc-static
|
||||
tests-static += tst-cleanup-start-stop-gc-static tst-cleanup-nostart-stop-gc-static
|
||||
tests-special += $(objpfx)tst-cleanup-start-stop-gc-cmp.out \
|
||||
$(objpfx)tst-cleanup-start-stop-gc-static-cmp.out \
|
||||
$(objpfx)tst-cleanup-nostart-stop-gc-cmp.out \
|
||||
$(objpfx)tst-cleanup-nostart-stop-gc-static-cmp.out
|
||||
LDFLAGS-tst-cleanup-start-stop-gc := -Wl,--gc-sections,-z,start-stop-gc
|
||||
LDFLAGS-tst-cleanup-start-stop-gc-static := -Wl,--gc-sections,-z,start-stop-gc
|
||||
LDFLAGS-tst-cleanup-nostart-stop-gc := -Wl,--gc-sections,-z,nostart-stop-gc
|
||||
LDFLAGS-tst-cleanup-nostart-stop-gc-static := -Wl,--gc-sections,-z,nostart-stop-gc
|
||||
endif
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
@ -224,6 +244,14 @@ $(objpfx)tst_wprintf2.out: $(gen-locales)
|
||||
$(objpfx)tst-wfile-sync.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
define gen-tst-cleanup
|
||||
$(objpfx)tst-cleanup-$1-cmp.out: tst-cleanup.exp $(objpfx)tst-cleanup-$1.out
|
||||
cmp $$^ > $$@; $$(evaluate-test)
|
||||
endef
|
||||
|
||||
$(foreach t,default default-static start-stop-gc start-stop-gc-static nostart-stop-gc nostart-stop-gc-static, \
|
||||
$(eval $(call gen-tst-cleanup,$(t))))
|
||||
|
||||
$(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' \
|
||||
$(common-objpfx)libio/; \
|
||||
|
1
libio/tst-cleanup-default-static.c
Normal file
1
libio/tst-cleanup-default-static.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
1
libio/tst-cleanup-default.c
Normal file
1
libio/tst-cleanup-default.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
1
libio/tst-cleanup-nostart-stop-gc-static.c
Normal file
1
libio/tst-cleanup-nostart-stop-gc-static.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
1
libio/tst-cleanup-nostart-stop-gc.c
Normal file
1
libio/tst-cleanup-nostart-stop-gc.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
1
libio/tst-cleanup-start-stop-gc-static.c
Normal file
1
libio/tst-cleanup-start-stop-gc-static.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
1
libio/tst-cleanup-start-stop-gc.c
Normal file
1
libio/tst-cleanup-start-stop-gc.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup.c"
|
34
libio/tst-cleanup.c
Normal file
34
libio/tst-cleanup.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Test that stdout is flushed after atexit callbacks were run, even if the
|
||||
* executable is linked with --gc-sections. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
hook (void)
|
||||
{
|
||||
puts ("hello");
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
atexit (hook);
|
||||
}
|
1
libio/tst-cleanup.exp
Normal file
1
libio/tst-cleanup.exp
Normal file
@ -0,0 +1 @@
|
||||
hello
|
Loading…
Reference in New Issue
Block a user