Message ID | 20210322040044.2559211-1-maskray@google.com |
---|---|
State | New |
Headers | show |
Series | [v2] Set the retain attribute on _elf_set_element if CC supports [BZ #27492] | expand |
On Sun, Mar 21, 2021 at 9:01 PM Fangrui Song via Libc-alpha <libc-alpha@sourceware.org> wrote: > > 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). > --- > config.h.in | 3 +++ > configure | 23 +++++++++++++++++++++++ > configure.ac | 16 ++++++++++++++++ > include/libc-symbols.h | 30 +++++++++++++++++++++--------- > 4 files changed, 63 insertions(+), 9 deletions(-) > > diff --git a/config.h.in b/config.h.in > index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 > --- a/include/libc-symbols.h > +++ b/include/libc-symbols.h > @@ -373,17 +373,29 @@ for linking") > > /* These are all done the same way in ELF. > There is a new section created for each set. */ > -#ifdef SHARED > +#ifdef HAVE_GCC_RETAIN > +# ifdef SHARED > /* 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) You should define __attribute_used_and_retain__ instead. > + 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, retain, section (#set))) = &(symbol) > +# else > +# define _elf_set_element(set, symbol) \ > + static const void *const __elf_set_##set##_element_##symbol##__ \ > + __attribute__ ((used, retain, section (#set))) = &(symbol) > +# endif > #else > -# define _elf_set_element(set, symbol) \ > - static const void *const __elf_set_##set##_element_##symbol##__ \ > - __attribute__ ((used, section (#set))) = &(symbol) > -#endif > +# ifdef SHARED > +# define _elf_set_element(set, symbol) \ > + static const void *__elf_set_##set##_element_##symbol##__ \ > + __attribute__ ((used, section (#set))) = &(symbol) > +# else > +# define _elf_set_element(set, symbol) \ > + static const void *const __elf_set_##set##_element_##symbol##__ \ > + __attribute__ ((used, section (#set))) = &(symbol) > +# endif > +#endif /* HAVE_GCC_RETAIN */ > > /* Define SET as a symbol set. This may be required (it is in a.out) to > be able to use the set's contents. */ > -- > 2.31.0.rc2.261.g7f71774620-goog > libc.a is an installed file. Does this work with older linkers?
On 2021-03-21, H.J. Lu wrote: >On Sun, Mar 21, 2021 at 9:01 PM Fangrui Song via Libc-alpha ><libc-alpha@sourceware.org> wrote: >> >> 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). >> --- >> config.h.in | 3 +++ >> configure | 23 +++++++++++++++++++++++ >> configure.ac | 16 ++++++++++++++++ >> include/libc-symbols.h | 30 +++++++++++++++++++++--------- >> 4 files changed, 63 insertions(+), 9 deletions(-) >> >> diff --git a/config.h.in b/config.h.in >> index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 >> --- a/include/libc-symbols.h >> +++ b/include/libc-symbols.h >> @@ -373,17 +373,29 @@ for linking") >> >> /* These are all done the same way in ELF. >> There is a new section created for each set. */ >> -#ifdef SHARED >> +#ifdef HAVE_GCC_RETAIN >> +# ifdef SHARED >> /* 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) > >You should define __attribute_used_and_retain__ instead. > >> + 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, retain, section (#set))) = &(symbol) >> +# else >> +# define _elf_set_element(set, symbol) \ >> + static const void *const __elf_set_##set##_element_##symbol##__ \ >> + __attribute__ ((used, retain, section (#set))) = &(symbol) >> +# endif >> #else >> -# define _elf_set_element(set, symbol) \ >> - static const void *const __elf_set_##set##_element_##symbol##__ \ >> - __attribute__ ((used, section (#set))) = &(symbol) >> -#endif >> +# ifdef SHARED >> +# define _elf_set_element(set, symbol) \ >> + static const void *__elf_set_##set##_element_##symbol##__ \ >> + __attribute__ ((used, section (#set))) = &(symbol) >> +# else >> +# define _elf_set_element(set, symbol) \ >> + static const void *const __elf_set_##set##_element_##symbol##__ \ >> + __attribute__ ((used, section (#set))) = &(symbol) >> +# endif >> +#endif /* HAVE_GCC_RETAIN */ >> >> /* Define SET as a symbol set. This may be required (it is in a.out) to >> be able to use the set's contents. */ >> -- >> 2.31.0.rc2.261.g7f71774620-goog >> > >libc.a is an installed file. Does this work with older linkers? > >-- >H.J. How about /* These are all done the same way in ELF. There is a new section created for each set. */ #ifdef HAVE_GCC_RETAIN # define attribute_used_retain_section(sec) \ __attribute__ ((used, retain, section (sec))) #else # define attribute_used_retain_section(sec) \ __attribute__ ((used, section (sec))) #endif #ifdef SHARED /* 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_retain_section(#set) = &(symbol) #else # define _elf_set_element(set, symbol) \ static const void *const __elf_set_##set##_element_##symbol##__ \ attribute_used_retain_section(#set) = &(symbol) #endif ? Yes, older linkers just ignore unknown section flags. That is the ELF spirit.
On Sun, Mar 21, 2021 at 9:40 PM Fangrui Song <maskray@google.com> wrote: > > On 2021-03-21, H.J. Lu wrote: > >On Sun, Mar 21, 2021 at 9:01 PM Fangrui Song via Libc-alpha > ><libc-alpha@sourceware.org> wrote: > >> > >> 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). > >> --- > >> config.h.in | 3 +++ > >> configure | 23 +++++++++++++++++++++++ > >> configure.ac | 16 ++++++++++++++++ > >> include/libc-symbols.h | 30 +++++++++++++++++++++--------- > >> 4 files changed, 63 insertions(+), 9 deletions(-) > >> > >> diff --git a/config.h.in b/config.h.in > >> index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 > >> --- a/include/libc-symbols.h > >> +++ b/include/libc-symbols.h > >> @@ -373,17 +373,29 @@ for linking") > >> > >> /* These are all done the same way in ELF. > >> There is a new section created for each set. */ > >> -#ifdef SHARED > >> +#ifdef HAVE_GCC_RETAIN > >> +# ifdef SHARED > >> /* 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) > > > >You should define __attribute_used_and_retain__ instead. > > > >> + 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, retain, section (#set))) = &(symbol) > >> +# else > >> +# define _elf_set_element(set, symbol) \ > >> + static const void *const __elf_set_##set##_element_##symbol##__ \ > >> + __attribute__ ((used, retain, section (#set))) = &(symbol) > >> +# endif > >> #else > >> -# define _elf_set_element(set, symbol) \ > >> - static const void *const __elf_set_##set##_element_##symbol##__ \ > >> - __attribute__ ((used, section (#set))) = &(symbol) > >> -#endif > >> +# ifdef SHARED > >> +# define _elf_set_element(set, symbol) \ > >> + static const void *__elf_set_##set##_element_##symbol##__ \ > >> + __attribute__ ((used, section (#set))) = &(symbol) > >> +# else > >> +# define _elf_set_element(set, symbol) \ > >> + static const void *const __elf_set_##set##_element_##symbol##__ \ > >> + __attribute__ ((used, section (#set))) = &(symbol) > >> +# endif > >> +#endif /* HAVE_GCC_RETAIN */ > >> > >> /* Define SET as a symbol set. This may be required (it is in a.out) to > >> be able to use the set's contents. */ > >> -- > >> 2.31.0.rc2.261.g7f71774620-goog > >> > > > >libc.a is an installed file. Does this work with older linkers? > > > >-- > >H.J. > > How about > > /* These are all done the same way in ELF. > There is a new section created for each set. */ > #ifdef HAVE_GCC_RETAIN > # define attribute_used_retain_section(sec) \ > __attribute__ ((used, retain, section (sec))) > #else __attribute_used_and_retain__ is more flex and can be used without section. > # define attribute_used_retain_section(sec) \ > __attribute__ ((used, section (sec))) > #endif > #ifdef SHARED > /* 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_retain_section(#set) = &(symbol) > #else > # define _elf_set_element(set, symbol) \ > static const void *const __elf_set_##set##_element_##symbol##__ \ > attribute_used_retain_section(#set) = &(symbol) > #endif > ? Yes, older linkers just ignore unknown section flags. That is the ELF spirit.
On 2021-03-22, H.J. Lu wrote: >On Sun, Mar 21, 2021 at 9:40 PM Fangrui Song <maskray@google.com> wrote: >> >> On 2021-03-21, H.J. Lu wrote: >> >On Sun, Mar 21, 2021 at 9:01 PM Fangrui Song via Libc-alpha >> ><libc-alpha@sourceware.org> wrote: >> >> >> >> 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). >> >> --- >> >> config.h.in | 3 +++ >> >> configure | 23 +++++++++++++++++++++++ >> >> configure.ac | 16 ++++++++++++++++ >> >> include/libc-symbols.h | 30 +++++++++++++++++++++--------- >> >> 4 files changed, 63 insertions(+), 9 deletions(-) >> >> >> >> diff --git a/config.h.in b/config.h.in >> >> index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 >> >> --- a/include/libc-symbols.h >> >> +++ b/include/libc-symbols.h >> >> @@ -373,17 +373,29 @@ for linking") >> >> >> >> /* These are all done the same way in ELF. >> >> There is a new section created for each set. */ >> >> -#ifdef SHARED >> >> +#ifdef HAVE_GCC_RETAIN >> >> +# ifdef SHARED >> >> /* 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) >> > >> >You should define __attribute_used_and_retain__ instead. >> > >> >> + 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, retain, section (#set))) = &(symbol) >> >> +# else >> >> +# define _elf_set_element(set, symbol) \ >> >> + static const void *const __elf_set_##set##_element_##symbol##__ \ >> >> + __attribute__ ((used, retain, section (#set))) = &(symbol) >> >> +# endif >> >> #else >> >> -# define _elf_set_element(set, symbol) \ >> >> - static const void *const __elf_set_##set##_element_##symbol##__ \ >> >> - __attribute__ ((used, section (#set))) = &(symbol) >> >> -#endif >> >> +# ifdef SHARED >> >> +# define _elf_set_element(set, symbol) \ >> >> + static const void *__elf_set_##set##_element_##symbol##__ \ >> >> + __attribute__ ((used, section (#set))) = &(symbol) >> >> +# else >> >> +# define _elf_set_element(set, symbol) \ >> >> + static const void *const __elf_set_##set##_element_##symbol##__ \ >> >> + __attribute__ ((used, section (#set))) = &(symbol) >> >> +# endif >> >> +#endif /* HAVE_GCC_RETAIN */ >> >> >> >> /* Define SET as a symbol set. This may be required (it is in a.out) to >> >> be able to use the set's contents. */ >> >> -- >> >> 2.31.0.rc2.261.g7f71774620-goog >> >> >> > >> >libc.a is an installed file. Does this work with older linkers? >> > >> >-- >> >H.J. >> >> How about >> >> /* These are all done the same way in ELF. >> There is a new section created for each set. */ >> #ifdef HAVE_GCC_RETAIN >> # define attribute_used_retain_section(sec) \ >> __attribute__ ((used, retain, section (sec))) >> #else > >__attribute_used_and_retain__ is more flex and can be used >without section. > >> # define attribute_used_retain_section(sec) \ >> __attribute__ ((used, section (sec))) >> #endif >> #ifdef SHARED >> /* 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_retain_section(#set) = &(symbol) >> #else >> # define _elf_set_element(set, symbol) \ >> static const void *const __elf_set_##set##_element_##symbol##__ \ >> attribute_used_retain_section(#set) = &(symbol) >> #endif >> ? Yes, older linkers just ignore unknown section flags. That is the ELF spirit. > > > >-- >H.J. +#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. */ @@ -377,12 +383,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
On Mon, Mar 22, 2021 at 9:15 PM Fangrui Song <maskray@google.com> wrote: > > > On 2021-03-22, H.J. Lu wrote: > >On Sun, Mar 21, 2021 at 9:40 PM Fangrui Song <maskray@google.com> wrote: > >> > >> On 2021-03-21, H.J. Lu wrote: > >> >On Sun, Mar 21, 2021 at 9:01 PM Fangrui Song via Libc-alpha > >> ><libc-alpha@sourceware.org> wrote: > >> >> > >> >> 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). > >> >> --- > >> >> config.h.in | 3 +++ > >> >> configure | 23 +++++++++++++++++++++++ > >> >> configure.ac | 16 ++++++++++++++++ > >> >> include/libc-symbols.h | 30 +++++++++++++++++++++--------- > >> >> 4 files changed, 63 insertions(+), 9 deletions(-) > >> >> > >> >> diff --git a/config.h.in b/config.h.in > >> >> index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 > >> >> --- a/include/libc-symbols.h > >> >> +++ b/include/libc-symbols.h > >> >> @@ -373,17 +373,29 @@ for linking") > >> >> > >> >> /* These are all done the same way in ELF. > >> >> There is a new section created for each set. */ > >> >> -#ifdef SHARED > >> >> +#ifdef HAVE_GCC_RETAIN > >> >> +# ifdef SHARED > >> >> /* 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) > >> > > >> >You should define __attribute_used_and_retain__ instead. > >> > > >> >> + 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, retain, section (#set))) = &(symbol) > >> >> +# else > >> >> +# define _elf_set_element(set, symbol) \ > >> >> + static const void *const __elf_set_##set##_element_##symbol##__ \ > >> >> + __attribute__ ((used, retain, section (#set))) = &(symbol) > >> >> +# endif > >> >> #else > >> >> -# define _elf_set_element(set, symbol) \ > >> >> - static const void *const __elf_set_##set##_element_##symbol##__ \ > >> >> - __attribute__ ((used, section (#set))) = &(symbol) > >> >> -#endif > >> >> +# ifdef SHARED > >> >> +# define _elf_set_element(set, symbol) \ > >> >> + static const void *__elf_set_##set##_element_##symbol##__ \ > >> >> + __attribute__ ((used, section (#set))) = &(symbol) > >> >> +# else > >> >> +# define _elf_set_element(set, symbol) \ > >> >> + static const void *const __elf_set_##set##_element_##symbol##__ \ > >> >> + __attribute__ ((used, section (#set))) = &(symbol) > >> >> +# endif > >> >> +#endif /* HAVE_GCC_RETAIN */ > >> >> > >> >> /* Define SET as a symbol set. This may be required (it is in a.out) to > >> >> be able to use the set's contents. */ > >> >> -- > >> >> 2.31.0.rc2.261.g7f71774620-goog > >> >> > >> > > >> >libc.a is an installed file. Does this work with older linkers? > >> > > >> >-- > >> >H.J. > >> > >> How about > >> > >> /* These are all done the same way in ELF. > >> There is a new section created for each set. */ > >> #ifdef HAVE_GCC_RETAIN > >> # define attribute_used_retain_section(sec) \ > >> __attribute__ ((used, retain, section (sec))) > >> #else > > > >__attribute_used_and_retain__ is more flex and can be used > >without section. > > > >> # define attribute_used_retain_section(sec) \ > >> __attribute__ ((used, section (sec))) > >> #endif > >> #ifdef SHARED > >> /* 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_retain_section(#set) = &(symbol) > >> #else > >> # define _elf_set_element(set, symbol) \ > >> static const void *const __elf_set_##set##_element_##symbol##__ \ > >> attribute_used_retain_section(#set) = &(symbol) > >> #endif > >> ? Yes, older linkers just ignore unknown section flags. That is the ELF spirit. > > > > > > > >-- > >H.J. > > +#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. */ > @@ -377,12 +383,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 > Please submit a v2 patch. Thanks.
diff --git a/config.h.in b/config.h.in index f21bf04e47..cc875e90f9 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 37cef37413..28494de748 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 16b15b6f90..94ad713820 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 c83e550b03..f8eafcf1f3 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -373,17 +373,29 @@ for linking") /* These are all done the same way in ELF. There is a new section created for each set. */ -#ifdef SHARED +#ifdef HAVE_GCC_RETAIN +# ifdef SHARED /* 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) + 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, retain, section (#set))) = &(symbol) +# else +# define _elf_set_element(set, symbol) \ + static const void *const __elf_set_##set##_element_##symbol##__ \ + __attribute__ ((used, retain, section (#set))) = &(symbol) +# endif #else -# define _elf_set_element(set, symbol) \ - static const void *const __elf_set_##set##_element_##symbol##__ \ - __attribute__ ((used, section (#set))) = &(symbol) -#endif +# ifdef SHARED +# define _elf_set_element(set, symbol) \ + static const void *__elf_set_##set##_element_##symbol##__ \ + __attribute__ ((used, section (#set))) = &(symbol) +# else +# define _elf_set_element(set, symbol) \ + static const void *const __elf_set_##set##_element_##symbol##__ \ + __attribute__ ((used, section (#set))) = &(symbol) +# endif +#endif /* HAVE_GCC_RETAIN */ /* Define SET as a symbol set. This may be required (it is in a.out) to be able to use the set's contents. */