public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Carlos O'Donell <carlos@redhat.com>
To: Adhemerval Zanella <adhemerval.zanella@linaro.org>,
	libc-alpha@sourceware.org, Florian Weimer <fweimer@redhat.com>
Subject: Re: [PATCH v3 1/4] Move libc_freeres_ptrs and libc_subfreeres to hidden/weak functions
Date: Sat, 4 Mar 2023 12:37:07 -0500	[thread overview]
Message-ID: <35cd3223-8766-3b6f-2126-ea99d90ec1cb@redhat.com> (raw)
In-Reply-To: <20221227211145.3765256-2-adhemerval.zanella@linaro.org>

On 12/27/22 16:11, Adhemerval Zanella via Libc-alpha wrote:
> They are both used by __libc_freeres to free all library malloc
> allocated resources to help tooling like mtrace or valgrind on

s/on/with/g

> memory leak tracking.
> 
> The current scheme uses assembly markers and linker script entries
> to consolidate the free routines function pointers on RELRO segment

s/routines/routine/g
s/on/in the/g

> and to be freed buffers on BSS.

s/on/in/g

> 
> This patch changes it to use specific free functions for
> libc_freeres_ptrs buffers and call the function pointer array directly
> with call_function_static_weak.

Excellent work here. This completes a long-standing transition from magic sections to
explicit calls. I really like the direction you go with this.

> 
> It allows to remove both the internal macros and the linker

s/to remove/the removal of/g

> script sections.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> 
> Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
> ---
>  Makerules                                     |   7 -
>  crypt/md5-crypt.c                             |   7 +-
>  crypt/sha256-crypt.c                          |   7 +-
>  crypt/sha512-crypt.c                          |   7 +-
>  dlfcn/dlerror.h                               |   1 -
>  elf/dl-libc.c                                 |   5 +-
>  grp/fgetgrent.c                               |   5 +-
>  gshadow/fgetsgent.c                           |   5 +-
>  iconv/gconv_cache.c                           |   3 +-
>  iconv/gconv_conf.c                            |   3 +-
>  iconv/gconv_db.c                              |   6 +-
>  iconv/gconv_dl.c                              |   5 +-
>  include/libc-symbols.h                        |  73 --------
>  include/set-freeres.h                         | 142 ++++++++++++++++
>  inet/getnameinfo.c                            |   5 +-
>  inet/getnetgrent.c                            |   5 +-
>  inet/rcmd.c                                   |   5 +-
>  inet/rexec.c                                  |   5 +-
>  intl/dcigettext.c                             |   3 +-
>  intl/finddomain.c                             |   2 +-
>  intl/loadmsgcat.c                             |   1 -
>  intl/localealias.c                            |  15 +-
>  libio/fcloseall.c                             |   1 +
>  libio/genops.c                                |   8 +-
>  libio/libioP.h                                |   1 -
>  locale/loadarchive.c                          |   2 +-
>  locale/localeinfo.h                           |   4 +-
>  locale/setlocale.c                            |   4 +-
>  login/getutent.c                              |   5 +-
>  login/getutid.c                               |   6 +-
>  login/getutline.c                             |   5 +-
>  malloc/set-freeres.c                          | 156 +++++++++++++++---
>  malloc/thread-freeres.c                       |   9 +-
>  misc/efgcvt-template.c                        |   5 +-
>  misc/efgcvt.c                                 |   1 +
>  misc/fstab.c                                  |   3 +-
>  misc/hsearch.c                                |   4 -
>  misc/mntent.c                                 |   5 +-
>  misc/qefgcvt.c                                |   1 +
>  misc/unwind-link.c                            |   2 +-
>  nptl/nptlfreeres.c                            |   1 -
>  nscd/nscd_getgr_r.c                           |   3 +-
>  nscd/nscd_gethst_r.c                          |   3 +-
>  nscd/nscd_getpw_r.c                           |   3 +-
>  nscd/nscd_getserv_r.c                         |   3 +-
>  nscd/nscd_netgroup.c                          |   3 +-
>  nss/getXXbyYY.c                               |   7 +-
>  nss/getXXent.c                                |   7 +-
>  nss/nss_action.c                              |   2 +-
>  nss/nss_action.h                              |   3 -
>  nss/nss_database.c                            |   2 +-
>  nss/nss_database.h                            |   3 -
>  nss/nss_module.c                              |   2 +-
>  nss/nss_module.h                              |   3 -
>  posix/regcomp.c                               |   3 +-
>  posix/register-atfork.c                       |   3 +-
>  pwd/fgetpwent.c                               |   5 +-
>  resolv/gai_misc.c                             |   6 +-
>  resolv/res-close.c                            |   2 -
>  resolv/res_hconf.c                            |  16 +-
>  resolv/resolv-internal.h                      |  14 ++
>  resolv/resolv_conf.c                          |   3 +-
>  resolv/tst-leaks2.c                           |   2 +
>  rt/aio_misc.c                                 |   6 +-
>  shadow/fgetspent.c                            |   5 +-
>  stdio-common/reg-modifier.c                   |   3 +-
>  stdio-common/reg-printf.c                     |   6 +-
>  stdio-common/reg-type.c                       |   6 +-
>  stdlib/exit.c                                 |   2 +-
>  stdlib/fmtmsg.c                               |   3 +-
>  stdlib/setenv.c                               |   3 +-
>  sunrpc/clnt_perr.c                            |   4 +-
>  sunrpc/rpc_thread.c                           |   1 -
>  sunrpc/tst-svc_register.c                     |   6 +-
>  sysdeps/generic/set-freeres-fp.h              |  19 +++
>  sysdeps/generic/set-freeres-os.h              |  19 +++
>  sysdeps/generic/set-freeres-system.h          |  27 +++
>  .../ldbl-128ibm-compat/ieee128-qefgcvt.c      |   1 +
>  .../ldbl-128ibm-compat/set-freeres-fp.h       |  22 +++
>  sysdeps/mach/hurd/bits/errno.h                |   1 -
>  sysdeps/posix/getaddrinfo.c                   |   5 +-
>  sysdeps/posix/ttyname.c                       |   4 +-
>  sysdeps/unix/sysv/linux/check_pf.c            |   3 +-
>  .../unix/sysv/linux/s390/s390-32/getutent.c   |   1 +
>  .../unix/sysv/linux/s390/s390-32/getutid.c    |   1 +
>  .../unix/sysv/linux/s390/s390-32/getutline.c  |   1 +
>  sysdeps/unix/sysv/linux/set-freeres-os.h      |  24 +++
>  sysdeps/unix/sysv/linux/ttyname.c             |   8 +-
>  time/tzfile.c                                 |   5 +-
>  time/tzset.c                                  |   3 +-
>  90 files changed, 584 insertions(+), 243 deletions(-)
>  create mode 100644 include/set-freeres.h
>  create mode 100644 sysdeps/generic/set-freeres-fp.h
>  create mode 100644 sysdeps/generic/set-freeres-os.h
>  create mode 100644 sysdeps/generic/set-freeres-system.h
>  create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
>  create mode 100644 sysdeps/unix/sysv/linux/set-freeres-os.h
> 
> diff --git a/Makerules b/Makerules
> index 3226b7a12b..962b2cd90c 100644
> --- a/Makerules
> +++ b/Makerules
> @@ -560,14 +560,7 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
>  		  -Wl,--verbose 2>/dev/null | \
>  	  sed > $@T \
>  	      -e '/^=========/,/^=========/!d;/^=========/d' \
> -	      -e 's/^.*\*(\.dynbss).*$$/& \
> -		 PROVIDE(__start___libc_freeres_ptrs = .); \
> -		 *(__libc_freeres_ptrs) \
> -		 PROVIDE(__stop___libc_freeres_ptrs = .);/'\

OK. Glad to see these go.

>  	      -e 's@^.*\*(\.jcr).*$$@& \
> -		 PROVIDE(__start___libc_subfreeres = .);\
> -		 __libc_subfreeres : { *(__libc_subfreeres) }\
> -		 PROVIDE(__stop___libc_subfreeres = .);\

OK. Likewise. Neither of these sections should be ABI.

>  		 PROVIDE(__start___libc_IO_vtables = .);\
>  		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
>  		 PROVIDE(__stop___libc_IO_vtables = .);\
> diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c
> index 7c4fb9fb97..b902abb77e 100644
> --- a/crypt/md5-crypt.c
> +++ b/crypt/md5-crypt.c
> @@ -299,10 +299,7 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  char *
>  __md5_crypt (const char *key, const char *salt)
> @@ -326,11 +323,9 @@ __md5_crypt (const char *key, const char *salt)
>    return __md5_crypt_r (key, salt, buffer, buflen);
>  }
>  
> -#ifndef _LIBC
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
>  {
>    free (buffer);
>  }
> -#endif
> diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c
> index a98a968a8b..ce3b2fba79 100644
> --- a/crypt/sha256-crypt.c
> +++ b/crypt/sha256-crypt.c
> @@ -386,10 +386,7 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* This entry point is equivalent to the `crypt' function in Unix
>     libcs.  */
> @@ -418,11 +415,9 @@ __sha256_crypt (const char *key, const char *salt)
>    return __sha256_crypt_r (key, salt, buffer, buflen);
>  }
>  
> -#ifndef _LIBC
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
>  {
>    free (buffer);
>  }
> -#endif
> diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c
> index ea13527c09..c0469c363e 100644
> --- a/crypt/sha512-crypt.c
> +++ b/crypt/sha512-crypt.c
> @@ -408,10 +408,7 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* This entry point is equivalent to the `crypt' function in Unix
>     libcs.  */
> @@ -440,11 +437,9 @@ __sha512_crypt (const char *key, const char *salt)
>    return __sha512_crypt_r (key, salt, buffer, buflen);
>  }
>  
> -#ifndef _LIBC
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
>  {
>    free (buffer);
>  }
> -#endif
> diff --git a/dlfcn/dlerror.h b/dlfcn/dlerror.h
> index d088cf40d9..e555ed7835 100644
> --- a/dlfcn/dlerror.h
> +++ b/dlfcn/dlerror.h
> @@ -87,6 +87,5 @@ static struct dl_action_result *const dl_action_result_malloc_failed
>     reporting via dlerror.  */
>  extern __thread struct dl_action_result *__libc_dlerror_result
>    attribute_tls_model_ie;
> -void __libc_dlerror_result_free (void) attribute_hidden;
>  
>  #endif /* _DLERROR_H */
> diff --git a/elf/dl-libc.c b/elf/dl-libc.c
> index 266e068da6..3299febe52 100644
> --- a/elf/dl-libc.c
> +++ b/elf/dl-libc.c
> @@ -228,7 +228,7 @@ __libc_dlclose (void *map)
>  }
>  
>  
> -static bool __libc_freeres_fn_section
> +static bool
>  free_slotinfo (struct dtv_slotinfo_list **elemp)
>  {
>    size_t cnt;
> @@ -256,7 +256,8 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__dl_libc_freemem (void)
>  {
>    struct link_map *l;
>    struct r_search_path_elem *d;
> diff --git a/grp/fgetgrent.c b/grp/fgetgrent.c
> index fd2b4d32d6..cbbd9e2489 100644
> --- a/grp/fgetgrent.c
> +++ b/grp/fgetgrent.c
> @@ -20,12 +20,13 @@
>  #include <libc-lock.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one entry from the given stream.  */
>  struct group *
> @@ -82,3 +83,5 @@ fgetgrent (FILE *stream)
>  
>    return result;
>  }
> +
> +weak_alias (buffer, __libc_fgetgrent_freemem_ptr)
> diff --git a/gshadow/fgetsgent.c b/gshadow/fgetsgent.c
> index 02f9c7d643..1b1ac6cd97 100644
> --- a/gshadow/fgetsgent.c
> +++ b/gshadow/fgetsgent.c
> @@ -20,6 +20,7 @@
>  #include <gshadow.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  
>  /* A reasonable size for a buffer to start with.  */
> @@ -28,7 +29,7 @@
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one shadow entry from the given stream.  */
>  struct sgrp *
> @@ -85,3 +86,5 @@ fgetsgent (FILE *stream)
>  
>    return result;
>  }
> +
> +weak_alias (buffer, __libc_fgetsgent_freeres_ptr);
> diff --git a/iconv/gconv_cache.c b/iconv/gconv_cache.c
> index 8d47545c41..e250228561 100644
> --- a/iconv/gconv_cache.c
> +++ b/iconv/gconv_cache.c
> @@ -449,7 +449,8 @@ __gconv_release_cache (struct __gconv_step *steps, size_t nsteps)
>  
>  
>  /* Free all resources if necessary.  */
> -libc_freeres_fn (free_mem)
> +void
> +__gconv_cache_freemem (void)
>  {
>    if (cache_malloced)
>      free (gconv_cache);
> diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
> index f069e28323..608109c040 100644
> --- a/iconv/gconv_conf.c
> +++ b/iconv/gconv_conf.c
> @@ -530,7 +530,8 @@ __gconv_load_conf (void)
>  
>  
>  /* Free all resources if necessary.  */
> -libc_freeres_fn (free_mem)
> +void
> +__gconv_conf_freemem (void)
>  {
>    if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem)
>      free ((void *) __gconv_path_elem);
> diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c
> index 4943c954a3..7aeae5993c 100644
> --- a/iconv/gconv_db.c
> +++ b/iconv/gconv_db.c
> @@ -169,7 +169,7 @@ add_derivation (const char *fromset, const char *toset,
>       not all memory will be freed.  */
>  }
>  
> -static void __libc_freeres_fn_section
> +static void
>  free_derivation (void *p)
>  {
>    struct known_derivation *deriv = (struct known_derivation *) p;
> @@ -793,7 +793,6 @@ __gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
>  
>  /* Free the modules mentioned.  */
>  static void
> -__libc_freeres_fn_section
>  free_modules_db (struct gconv_module *node)
>  {
>    if (node->left != NULL)
> @@ -812,7 +811,8 @@ free_modules_db (struct gconv_module *node)
>  
>  
>  /* Free all resources if necessary.  */
> -libc_freeres_fn (free_mem)
> +void
> +__gconv_db_freemem (void)
>  {
>    /* First free locale memory.  This needs to be done before freeing
>       derivations, as ctype cleanup functions dereference steps arrays which we
> diff --git a/iconv/gconv_dl.c b/iconv/gconv_dl.c
> index 5ed982636a..6cc05e42fc 100644
> --- a/iconv/gconv_dl.c
> +++ b/iconv/gconv_dl.c
> @@ -184,7 +184,7 @@ __gconv_release_shlib (struct __gconv_loaded_object *handle)
>  
>  
>  /* We run this if we debug the memory allocation.  */
> -static void __libc_freeres_fn_section
> +static void
>  do_release_all (void *nodep)
>  {
>    struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
> @@ -196,7 +196,8 @@ do_release_all (void *nodep)
>    free (obj);
>  }
>  
> -libc_freeres_fn (free_mem)
> +void
> +__gconv_dl_freemem (void)
>  {
>    __tdestroy (loaded, do_release_all);
>    loaded = NULL;
> diff --git a/include/libc-symbols.h b/include/libc-symbols.h
> index f4437ff6ad..a1d422131f 100644
> --- a/include/libc-symbols.h
> +++ b/include/libc-symbols.h
> @@ -237,79 +237,6 @@ requires at runtime the shared libraries from the glibc version used \
>  for linking")
>  #endif
>  
> -/* Resource Freeing Hooks:
> -
> -   Normally a process exits and the OS cleans up any allocated
> -   memory.  However, when tooling like mtrace or valgrind is monitoring
> -   the process we need to free all resources that are part of the
> -   process in order to provide the consistency required to track
> -   memory leaks.
> -
> -   A single public API exists and is __libc_freeres(), and this is used
> -   by applications like valgrind to freee resouces.
> -
> -   There are 3 cases:
> -
> -   (a) __libc_freeres
> -
> -	In this case all you need to do is define the freeing routine:
> -
> -	foo.c:
> -	libfoo_freeres_fn (foo_freeres)
> -	{
> -	  complex_free (mem);
> -	}
> -
> -	This ensures the function is called at the right point to free
> -	resources.
> -
> -   (b) __libc_freeres_ptr
> -
> -	The framework for (a) iterates over the list of pointers-to-free
> -	in (b) and frees them.
> -
> -	foo.c:
> -	libc_freeres_ptr (static char *foo_buffer);
> -
> -	Freeing these resources alaways happens last and is equivalent
> -	to registering a function that does 'free (foo_buffer)'.
> -
> -   (c) Explicit lists of free routines to call or objects to free.
> -
> -	It is the intended goal to remove (a) and (b) which have some
> -	non-determinism based on link order, and instead use explicit
> -	lists of functions and frees to resolve cleanup ordering issues
> -	and make it easy to debug and maintain.
> -
> -	As of today the following subsystems use (c):
> -
> -	Per-thread cleanup:
> -	* malloc/thread-freeres.c
> -
> -	libdl cleanup:
> -	* dlfcn/dlfreeres.c
> -
> -	libpthread cleanup:
> -	* nptl/nptlfreeres.c
> -
> -	So if you need any shutdown routines to run you should add them
> -	directly to the appropriate subsystem's shutdown list.  */
> -
> -/* Resource pointers to free in libc.so.  */
> -#define libc_freeres_ptr(decl) \
> -  __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
> -  decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
> -
> -/* Resource freeing functions from libc.so go in this section.  */
> -#define __libc_freeres_fn_section \
> -  __attribute__ ((__used__, section ("__libc_freeres_fn")))
> -
> -/* Resource freeing functions for libc.so.  */
> -#define libc_freeres_fn(name) \
> -  static void name (void) __attribute_used__ __libc_freeres_fn_section;	\
> -  text_set_element (__libc_subfreeres, name);				\
> -  static void name (void)
> -

OK. Perfect, with the macros missing any uses backported immediately fail.

>  /* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes
>     alias to ORIGINAL, when the assembler supports such declarations
>     (such as in ELF).
> diff --git a/include/set-freeres.h b/include/set-freeres.h
> new file mode 100644
> index 0000000000..b7f66519a3
> --- /dev/null
> +++ b/include/set-freeres.h
> @@ -0,0 +1,142 @@
> +/* Macros for internal resource Freeing Hooks.
> +   Copyright (C) 2022 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/>.  */
> +
> +#ifndef _SET_FREERES_H
> +#define _SET_FREERES_H 1
> +
> +#include <shlib-compat.h>
> +#include <printf.h>
> +#include <time.h>
> +#include <resolv/resolv-internal.h>
> +
> +/* Resource Freeing Hooks:
> +
> +   Normally a process exits and the OS cleans up any allocated
> +   memory.  However, when tooling like mtrace or valgrind is monitoring
> +   the process we need to free all resources that are part of the
> +   process in order to provide the consistency required to track
> +   memory leaks.
> +
> +   A single public API exists and is __libc_freeres, and this is used
> +   by applications like valgrind to freee resouces.
> +
> +   Each free routines must be explicit listed below.  */
> +
> +/* From libc.so.  */
> +extern void __dl_libc_freemem (void) attribute_hidden;
> +extern void __hdestroy (void) attribute_hidden;
> +extern void __gconv_cache_freemem (void) attribute_hidden;
> +extern void __gconv_conf_freemem (void) attribute_hidden;
> +extern void __gconv_db_freemem (void) attribute_hidden;
> +extern void __gconv_dl_freemem (void) attribute_hidden;
> +extern void __intl_freemem (void) attribute_hidden;
> +extern void __libio_freemem (void) attribute_hidden;
> +extern void __libc_fstab_freemem (void) attribute_hidden;
> +extern void __nscd_gr_map_freemem (void) attribute_hidden;
> +extern void __nscd_hst_map_freemem (void) attribute_hidden;
> +extern void __nscd_pw_map_freemem (void) attribute_hidden;
> +extern void __nscd_serv_map_freemem (void) attribute_hidden;
> +extern void __nscd_group_map_freemem (void) attribute_hidden;
> +extern void __libc_regcomp_freemem (void) attribute_hidden;
> +extern void __libc_atfork_freemem (void) attribute_hidden;
> +extern void __libc_resolv_conf_freemem (void) attribute_hidden;
> +extern void __res_thread_freeres (void) attribute_hidden;
> +extern void __libc_printf_freemem (void) attribute_hidden;
> +extern void __libc_fmtmsg_freemem (void) attribute_hidden;
> +extern void __libc_setenv_freemem (void) attribute_hidden;
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_31)
> +extern void __rpc_freemem (void) attribute_hidden;
> +extern void __rpc_thread_destroy (void) attribute_hidden;
> +#endif
> +extern void __libc_getaddrinfo_freemem (void) attribute_hidden;
> +extern void __libc_tzset_freemem (void) attribute_hidden;
> +extern void __libc_localealias_freemem (void) attribute_hidden;
> +extern void __libc_getutent_freemem (void) attribute_hidden;
> +extern void __libc_getutline_freemem (void) attribute_hidden;
> +/* From nss/nss_module.c */
> +extern void __nss_module_freeres (void) attribute_hidden;
> +/* From nss/nss_action.c */
> +extern void __nss_action_freeres (void) attribute_hidden;
> +/* From nss/nss_database.c */
> +extern void __nss_database_freeres (void) attribute_hidden;
> +/* From libio/genops.c */
> +extern int _IO_cleanup (void) attribute_hidden;;
> +/* From dlfcn/dlerror.c */
> +extern void __libc_dlerror_result_free (void) attribute_hidden;
> +
> +/* From either libc.so or libpthread.so  */
> +extern void __libpthread_freeres (void) attribute_hidden;
> +/* From either libc.so or libanl.so  */
> +#if PTHREAD_IN_LIBC
> +extern void __gai_freemem (void) attribute_hidden;
> +/* From either libc.so or librt.so  */
> +extern void __aio_freemem (void) attribute_hidden;
> +#endif
> +
> +/* From libc.so  */
> +extern char * __libc_fgetgrent_freemem_ptr attribute_hidden;
> +extern char * __libc_fgetsgent_freeres_ptr attribute_hidden;
> +extern char * __libc_getnetgrent_freemem_ptr attribute_hidden;
> +extern char * __libc_rcmd_freemem_ptr attribute_hidden;
> +extern char * __libc_rexec_freemem_ptr attribute_hidden;
> +extern void * __libc_mntent_freemem_ptr attribute_hidden;
> +extern char * __libc_fgetpwent_freemem_ptr attribute_hidden;
> +extern struct netaddr * __libc_resolv_res_hconf_freemem_ptr attribute_hidden;
> +extern char * __libc_fgetspent_freemem_ptr attribute_hidden;
> +extern __time64_t * __libc_tzfile_freemem_ptr attribute_hidden;
> +extern char * __libc_getnameinfo_freemem_ptr attribute_hidden;
> +extern struct utmp * __libc_getutent_freemem_ptr attribute_hidden;
> +extern struct utmp * __libc_getutid_freemem_ptr attribute_hidden;
> +extern struct utmp * __libc_getutline_freemem_ptr attribute_hidden;
> +extern printf_arginfo_size_function ** __libc_reg_printf_freemem_ptr
> +    attribute_hidden;
> +extern printf_va_arg_function ** __libc_reg_type_freemem_ptr
> +    attribute_hidden;
> +/* From nss/getXXbyYY.c  */
> +extern char * __libc_getgrgid_freemem_ptr attribute_hidden;
> +extern char * __libc_getgrnam_freemem_ptr attribute_hidden;
> +extern char * __libc_getpwnam_freemem_ptr attribute_hidden;
> +extern char * __libc_getpwuid_freemem_ptr attribute_hidden;
> +extern char * __libc_getspnam_freemem_ptr attribute_hidden;
> +extern char * __libc_getaliasbyname_freemem_ptr attribute_hidden;
> +extern char * __libc_gethostbyaddr_freemem_ptr attribute_hidden;
> +extern char * __libc_gethostbyname_freemem_ptr attribute_hidden;
> +extern char * __libc_gethostbyname2_freemem_ptr attribute_hidden;
> +extern char * __libc_getnetbyaddr_freemem_ptr attribute_hidden;
> +extern char * __libc_getnetbyname_freemem_ptr attribute_hidden;
> +extern char * __libc_getprotobynumber_freemem_ptr attribute_hidden;
> +extern char * __libc_getprotobyname_freemem_ptr attribute_hidden;
> +extern char * __libc_getrpcbyname_freemem_ptr attribute_hidden;
> +extern char * __libc_getrpcbynumber_freemem_ptr attribute_hidden;
> +extern char * __libc_getservbyname_freemem_ptr attribute_hidden;
> +extern char * __libc_getservbyport_freemem_ptr attribute_hidden;
> +/* From nss/getXXent.c */
> +extern char * __libc_getgrent_freemem_ptr attribute_hidden;
> +extern char * __libc_getpwent_freemem_ptr attribute_hidden;
> +extern char * __libc_getspent_freemem_ptr attribute_hidden;
> +extern char * __libc_getaliasent_freemem_ptr attribute_hidden;
> +extern char * __libc_gethostent_freemem_ptr attribute_hidden;
> +extern char * __libc_getnetent_freemem_ptr attribute_hidden;
> +extern char * __libc_getprotoent_freemem_ptr attribute_hidden;
> +extern char * __libc_getrpcent_freemem_ptr attribute_hidden;
> +extern char * __libc_getservent_freemem_ptr attribute_hidden;
> +/* From misc/efgcvt-template.c  */
> +extern char * __libc_efgcvt_freemem_ptr attribute_hidden;
> +extern char * __libc_qefgcvt_freemem_ptr attribute_hidden;
> +
> +#endif

OK. List all the functions, and pointers.

> diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c
> index 4733be6f5b..4b1309979f 100644
> --- a/inet/getnameinfo.c
> +++ b/inet/getnameinfo.c
> @@ -72,12 +72,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  #include <libc-lock.h>
>  #include <scratch_buffer.h>
>  #include <net-internal.h>
> +#include <set-freeres.h>
>  
>  #ifndef min
>  # define min(x,y) (((x) > (y)) ? (y) : (x))
>  #endif /* min */
>  
> -libc_freeres_ptr (static char *domain);
> +static char *domain;
>  
>  /* Former NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES flags,
>     now ignored.  */
> @@ -556,3 +557,5 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
>    return 0;
>  }
>  libc_hidden_def (getnameinfo)
> +
> +weak_alias (domain, __libc_getnameinfo_freemem_ptr)
> diff --git a/inet/getnetgrent.c b/inet/getnetgrent.c
> index e354194b72..53ddb2fd75 100644
> --- a/inet/getnetgrent.c
> +++ b/inet/getnetgrent.c
> @@ -19,9 +19,10 @@
>  #include <netdb.h>
>  #include <stdlib.h>
>  #include <libc-lock.h>
> +#include <set-freeres.h>
>  
>  /* Static buffer for return value.  We allocate it when needed.  */
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  /* All three strings should fit in a block of 1kB size.  */
>  #define BUFSIZE 1024
>  
> @@ -47,3 +48,5 @@ getnetgrent (char **hostp, char **userp, char **domainp)
>  
>    return __getnetgrent_r (hostp, userp, domainp, buffer, BUFSIZE);
>  }
> +
> +weak_alias (buffer, __libc_getnetgrent_freemem_ptr)
> diff --git a/inet/rcmd.c b/inet/rcmd.c
> index 2b95fa11d8..ad8a894907 100644
> --- a/inet/rcmd.c
> +++ b/inet/rcmd.c
> @@ -80,6 +80,7 @@
>  #include <sys/uio.h>
>  #include <sigsetops.h>
>  #include <shlib-compat.h>
> +#include <set-freeres.h>
>  
>  
>  int __ivaliduser (FILE *, uint32_t, const char *, const char *);
> @@ -98,7 +99,7 @@ int iruserok (uint32_t raddr, int superuser, const char *ruser,
>  
>  libc_hidden_proto (iruserok_af)
>  
> -libc_freeres_ptr(static char *ahostbuf);
> +static char *ahostbuf;
>  
>  int
>  rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
> @@ -817,3 +818,5 @@ __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
>  
>      return retval;
>  }
> +
> +weak_alias (ahostbuf, __libc_rcmd_freemem_ptr)
> diff --git a/inet/rexec.c b/inet/rexec.c
> index c647b7ac34..1985fa4418 100644
> --- a/inet/rexec.c
> +++ b/inet/rexec.c
> @@ -40,9 +40,10 @@
>  #include <string.h>
>  #include <unistd.h>
>  #include <sys/uio.h>
> +#include <set-freeres.h>
>  
>  int	rexecoptions;
> -libc_freeres_ptr (static char *ahostbuf);
> +static char *ahostbuf;
>  
>  int
>  rexec_af (char **ahost, int rport, const char *name, const char *pass,
> @@ -196,3 +197,5 @@ rexec (char **ahost, int rport, const char *name, const char *pass,
>  {
>  	return rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET);
>  }
> +
> +weak_alias (ahostbuf, __libc_rexec_freemem_ptr)
> diff --git a/intl/dcigettext.c b/intl/dcigettext.c
> index 1fc074a414..bfac152908 100644
> --- a/intl/dcigettext.c
> +++ b/intl/dcigettext.c
> @@ -1671,7 +1671,8 @@ mempcpy (void *dest, const void *src, size_t n)
>  #ifdef _LIBC
>  /* If we want to free all resources we have to do some work at
>     program's end.  */
> -libc_freeres_fn (free_mem)
> +void
> +__intl_freemem (void)
>  {
>    void *old;
>  
> diff --git a/intl/finddomain.c b/intl/finddomain.c
> index 416e28ad76..58de876e28 100644
> --- a/intl/finddomain.c
> +++ b/intl/finddomain.c
> @@ -185,7 +185,7 @@ out:
>  #ifdef _LIBC
>  /* This is called from iconv/gconv_db.c's free_mem, as locales must
>     be freed before freeing gconv steps arrays.  */
> -void __libc_freeres_fn_section
> +void
>  _nl_finddomain_subfreeres (void)
>  {
>    struct loaded_l10nfile *runp = _nl_loaded_domains;
> diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
> index 98d5f53232..0b98f233dd 100644
> --- a/intl/loadmsgcat.c
> +++ b/intl/loadmsgcat.c
> @@ -1284,7 +1284,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
>  
>  #ifdef _LIBC
>  void
> -__libc_freeres_fn_section
>  _nl_unload_domain (struct loaded_domain *domain)
>  {
>    size_t i;
> diff --git a/intl/localealias.c b/intl/localealias.c
> index b36092363a..4bf068d0ea 100644
> --- a/intl/localealias.c
> +++ b/intl/localealias.c
> @@ -126,14 +126,10 @@ struct alias_map
>  };
>  
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -
> -libc_freeres_ptr (static char *string_space);
> +static char *string_space;
>  static size_t string_space_act;
>  static size_t string_space_max;
> -libc_freeres_ptr (static struct alias_map *map);
> +static struct alias_map *map;
>  static size_t nmap;
>  static size_t maxmap;
>  
> @@ -439,3 +435,10 @@ alias_compare (const struct alias_map *map1, const struct alias_map *map2)
>    return c1 - c2;
>  #endif
>  }
> +
> +void
> +__libc_localealias_freemem (void)
> +{
> +  free (string_space);
> +  free (map);
> +}
> diff --git a/libio/fcloseall.c b/libio/fcloseall.c
> index 4e2a038d39..1ee8916078 100644
> --- a/libio/fcloseall.c
> +++ b/libio/fcloseall.c
> @@ -26,6 +26,7 @@
>  
>  #include "libioP.h"
>  #include <stdio.h>
> +#include <set-freeres.h>
>  
>  int
>  __fcloseall (void)
> diff --git a/libio/genops.c b/libio/genops.c
> index 8a7fc4f7c5..b3a0603a0a 100644
> --- a/libio/genops.c
> +++ b/libio/genops.c
> @@ -765,8 +765,8 @@ weak_alias (_IO_flush_all_linebuffered, _flushlbf)
>     actual buffer because this will happen anyway once the program
>     terminated.  If we do want to look for memory leaks we have to free
>     the buffers.  Whether something is freed is determined by the
> -   function sin the libc_freeres section.  Those are called as part of
> -   the atexit routine, just like _IO_cleanup.  The problem is we do
> +   function called by __libc_freeres (those are not called as part of
> +   the atexit routine, different from  _IO_cleanup).  The problem is we do
>     not know whether the freeres code is called first or _IO_cleanup.
>     if the former is the case, we set the DEALLOC_BUFFER variable to
>     true and _IO_unbuffer_all will take care of the rest.  If
> @@ -844,8 +844,8 @@ _IO_unbuffer_all (void)
>  #endif
>  }
>  
> -
> -libc_freeres_fn (buffer_free)
> +void
> +__libio_freemem (void)
>  {
>    dealloc_buffers = true;
>  
> diff --git a/libio/libioP.h b/libio/libioP.h
> index 3a5498bd65..8500c75fa0 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -491,7 +491,6 @@ libc_hidden_proto (_IO_wdo_write)
>  extern int _IO_flush_all_lockp (int);
>  extern int _IO_flush_all (void);
>  libc_hidden_proto (_IO_flush_all)
> -extern int _IO_cleanup (void);
>  extern void _IO_flush_all_linebuffered (void);
>  libc_hidden_proto (_IO_flush_all_linebuffered)
>  extern int _IO_new_fgetpos (FILE *, __fpos_t *);
> diff --git a/locale/loadarchive.c b/locale/loadarchive.c
> index fcc4913319..60ae1daa2c 100644
> --- a/locale/loadarchive.c
> +++ b/locale/loadarchive.c
> @@ -498,7 +498,7 @@ _nl_load_locale_from_archive (int category, const char **namep)
>    return lia->data[category];
>  }
>  
> -void __libc_freeres_fn_section
> +void
>  _nl_archive_subfreeres (void)
>  {
>    struct locale_in_archive *lia;
> diff --git a/locale/localeinfo.h b/locale/localeinfo.h
> index fd43033a19..1bf4215e71 100644
> --- a/locale/localeinfo.h
> +++ b/locale/localeinfo.h
> @@ -381,10 +381,10 @@ extern struct __locale_data *_nl_load_locale_from_archive (int category,
>  							   const char **namep)
>       attribute_hidden;
>  
> -/* Subroutine of setlocale's __libc_subfreeres hook.  */
> +/* Subroutine of setlocale's free resource.  */
>  extern void _nl_archive_subfreeres (void) attribute_hidden;
>  
> -/* Subroutine of gconv-db's __libc_subfreeres hook.  */
> +/* Subroutine of gconv-db's free resource.  */
>  extern void _nl_locale_subfreeres (void) attribute_hidden;
>  
>  /* Validate the contents of a locale file and set up the in-core
> diff --git a/locale/setlocale.c b/locale/setlocale.c
> index 56c14d8533..d1e773f46a 100644
> --- a/locale/setlocale.c
> +++ b/locale/setlocale.c
> @@ -468,7 +468,7 @@ setlocale (int category, const char *locale)
>  }
>  libc_hidden_def (setlocale)
>  
> -static void __libc_freeres_fn_section
> +static void
>  free_category (int category,
>  	       struct __locale_data *here, struct __locale_data *c_data)
>  {
> @@ -498,7 +498,7 @@ free_category (int category,
>  
>  /* This is called from iconv/gconv_db.c's free_mem, as locales must
>     be freed before freeing gconv steps arrays.  */
> -void __libc_freeres_fn_section
> +void
>  _nl_locale_subfreeres (void)
>  {
>  #ifdef NL_CURRENT_INDIRECT
> diff --git a/login/getutent.c b/login/getutent.c
> index 8d2f1207f8..9627843def 100644
> --- a/login/getutent.c
> +++ b/login/getutent.c
> @@ -17,10 +17,11 @@
>  
>  #include <stdlib.h>
>  #include <utmp.h>
> +#include <set-freeres.h>
>  
>  
>  /* Local buffer to store the result.  */
> -libc_freeres_ptr (static struct utmp *buffer);
> +static struct utmp *buffer;
>  
>  
>  struct utmp *
> @@ -42,3 +43,5 @@ __getutent (void)
>  }
>  libc_hidden_def (__getutent)
>  weak_alias (__getutent, getutent)
> +
> +weak_alias (buffer, __libc_getutent_freemem_ptr)
> diff --git a/login/getutid.c b/login/getutid.c
> index 303c178db1..87e662da63 100644
> --- a/login/getutid.c
> +++ b/login/getutid.c
> @@ -17,10 +17,10 @@
>  
>  #include <stdlib.h>
>  #include <utmp.h>
> -
> +#include <set-freeres.h>
>  
>  /* Local buffer to store the result.  */
> -libc_freeres_ptr (static struct utmp *buffer);
> +static struct utmp *buffer;
>  
>  struct utmp *
>  __getutid (const struct utmp *id)
> @@ -40,3 +40,5 @@ __getutid (const struct utmp *id)
>  }
>  libc_hidden_def (__getutid)
>  weak_alias (__getutid, getutid)
> +
> +weak_alias (buffer, __libc_getutid_freemem_ptr)
> diff --git a/login/getutline.c b/login/getutline.c
> index 661eff3a3c..837b70a151 100644
> --- a/login/getutline.c
> +++ b/login/getutline.c
> @@ -17,10 +17,11 @@
>  
>  #include <stdlib.h>
>  #include <utmp.h>
> +#include <set-freeres.h>
>  
>  
>  /* Local buffer to store the result.  */
> -libc_freeres_ptr (static struct utmp *buffer);
> +static struct utmp *buffer;
>  
>  
>  struct utmp *
> @@ -41,3 +42,5 @@ __getutline (const struct utmp *line)
>  }
>  libc_hidden_def (__getutline)
>  weak_alias (__getutline, getutline)
> +
> +weak_alias (buffer, __libc_getutline_freemem_ptr)
> diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
> index be8c2a35fc..45642c3658 100644
> --- a/malloc/set-freeres.c
> +++ b/malloc/set-freeres.c
> @@ -15,32 +15,62 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#include <array_length.h>
>  #include <atomic.h>
>  #include <stdlib.h>
> -#include <set-hooks.h>
>  #include <libc-internal.h>
>  #include <unwind-link.h>
> -#include <dlfcn/dlerror.h>
>  #include <ldsodefs.h>
> +#include <set-freeres.h>
> +#include <set-freeres-system.h>
> +
> +#ifndef SHARED
> +# pragma weak __nss_module_freeres
> +# pragma weak __nss_action_freeres
> +# pragma weak __nss_database_freeres
> +# pragma weak __dl_libc_freemem
> +# pragma weak __hdestroy
> +# pragma weak __gconv_cache_freemem
> +# pragma weak __gconv_conf_freemem
> +# pragma weak __gconv_db_freemem
> +# pragma weak __gconv_dl_freemem
> +# pragma weak __intl_freemem
> +# pragma weak __libio_freemem
> +# pragma weak __libc_fstab_freemem
> +# pragma weak __nscd_gr_map_freemem
> +# pragma weak __nscd_hst_map_freemem
> +# pragma weak __nscd_pw_map_freemem
> +# pragma weak __nscd_serv_map_freemem
> +# pragma weak __nscd_group_map_freemem
> +# pragma weak __libc_regcomp_freemem
> +# pragma weak __libc_atfork_freemem
> +# pragma weak __res_thread_freeres
> +# pragma weak __libc_resolv_conf_freemem
> +# pragma weak __libc_printf_freemem
> +# pragma weak __libc_fmtmsg_freemem
> +# pragma weak __libc_setenv_freemem
> +# pragma weak __rpc_freemem
> +# pragma weak __rpc_thread_destroy
> +# pragma weak __libc_getaddrinfo_freemem
> +# pragma weak __libc_tzset_freemem
> +# pragma weak __libc_localealias_freemem
> +# pragma weak __gai_freemem
> +# pragma weak __aio_freemem
> +# pragma weak __libpthread_freeres
> +# pragma weak __libc_dlerror_result_free
> +# pragma weak __check_pf_freemem
> +#endif
>  
> -#include "../nss/nsswitch.h"
> -#include "../libio/libioP.h"
> -
> -DEFINE_HOOK (__libc_subfreeres, (void));
> -
> -symbol_set_define (__libc_freeres_ptrs);
> -
> -extern void __libpthread_freeres (void)
> -#if PTHREAD_IN_LIBC && defined SHARED
> -/* It is possible to call __libpthread_freeres directly in shared
> -   builds with an integrated libpthread.  */
> -  attribute_hidden
> +#ifdef SHARED
> +# define call_free_static_weak(__ptr)				\
> +   free (__ptr)
>  #else
> -  __attribute__ ((weak))
> +# define call_free_static_weak(__ptr)				\
> +  if (&__ptr != NULL)						\
> +    free (__ptr);
>  #endif
> -  ;
>  
> -void __libc_freeres_fn_section
> +void
>  __libc_freeres (void)
>  {
>    /* This function might be called from different places.  So better
> @@ -49,8 +79,6 @@ __libc_freeres (void)
>  
>    if (!atomic_compare_and_exchange_bool_acq (&already_called, 1, 0))
>      {
> -      void *const *p;
> -
>        call_function_static_weak (__nss_module_freeres);
>        call_function_static_weak (__nss_action_freeres);
>        call_function_static_weak (__nss_database_freeres);
> @@ -58,7 +86,43 @@ __libc_freeres (void)
>        _IO_cleanup ();
>  
>        /* We run the resource freeing after IO cleanup.  */
> -      RUN_HOOK (__libc_subfreeres, ());
> +      call_function_static_weak (__dl_libc_freemem);
> +      call_function_static_weak (__hdestroy);
> +      call_function_static_weak (__gconv_cache_freemem);
> +      call_function_static_weak (__gconv_conf_freemem);
> +      call_function_static_weak (__gconv_db_freemem);
> +      call_function_static_weak (__gconv_dl_freemem);
> +      call_function_static_weak (__intl_freemem);
> +      call_function_static_weak (__libio_freemem);
> +      call_function_static_weak (__libc_fstab_freemem);
> +      call_function_static_weak (__nscd_gr_map_freemem);
> +      call_function_static_weak (__nscd_hst_map_freemem);
> +      call_function_static_weak (__nscd_pw_map_freemem);
> +      call_function_static_weak (__nscd_serv_map_freemem);
> +      call_function_static_weak (__nscd_group_map_freemem);
> +      call_function_static_weak (__libc_regcomp_freemem);
> +      call_function_static_weak (__libc_atfork_freemem);
> +      /* __res_thread_freeres deallocates the per-thread resolv_context);
> +	 which in turn drop the reference count of the current global object.
> +	 So it need to be before __libc_resolv_conf_freemem.  */
> +      call_function_static_weak (__res_thread_freeres);
> +      call_function_static_weak (__libc_resolv_conf_freemem);
> +      call_function_static_weak (__libc_printf_freemem);
> +      call_function_static_weak (__libc_fmtmsg_freemem);
> +      call_function_static_weak (__libc_setenv_freemem);
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_31)
> +      call_function_static_weak (__rpc_freemem);
> +      call_function_static_weak (__rpc_thread_destroy);
> +#endif
> +      call_function_static_weak (__libc_getaddrinfo_freemem);
> +      call_function_static_weak (__libc_tzset_freemem);
> +      call_function_static_weak (__libc_localealias_freemem);
> +
> +#if PTHREAD_IN_LIBC
> +      call_function_static_weak (__gai_freemem);
> +
> +      call_function_static_weak (__aio_freemem);
> +#endif
>  
>        call_function_static_weak (__libpthread_freeres);
>  
> @@ -72,9 +136,55 @@ __libc_freeres (void)
>        GLRO (dl_libc_freeres) ();
>  #endif
>  
> -      for (p = symbol_set_first_element (__libc_freeres_ptrs);
> -           !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
> -        free (*p);
> +      call_free_static_weak (__libc_fgetgrent_freemem_ptr);
> +      call_free_static_weak (__libc_fgetsgent_freeres_ptr);
> +      call_free_static_weak (__libc_getnetgrent_freemem_ptr);
> +      call_free_static_weak (__libc_rcmd_freemem_ptr);
> +      call_free_static_weak (__libc_rexec_freemem_ptr);
> +      call_free_static_weak (__libc_mntent_freemem_ptr);
> +      call_free_static_weak (__libc_fgetpwent_freemem_ptr);
> +      call_free_static_weak (__libc_resolv_res_hconf_freemem_ptr);
> +      call_free_static_weak (__libc_fgetspent_freemem_ptr);
> +      call_free_static_weak (__libc_tzfile_freemem_ptr);
> +      call_free_static_weak (__libc_getnameinfo_freemem_ptr);
> +      call_free_static_weak (__libc_getutent_freemem_ptr);
> +      call_free_static_weak (__libc_getutid_freemem_ptr);
> +      call_free_static_weak (__libc_getutline_freemem_ptr);
> +      call_free_static_weak (__libc_reg_printf_freemem_ptr);
> +      call_free_static_weak (__libc_reg_type_freemem_ptr);
> +
> +      call_free_static_weak (__libc_getgrgid_freemem_ptr);
> +      call_free_static_weak (__libc_getgrnam_freemem_ptr);
> +      call_free_static_weak (__libc_getpwnam_freemem_ptr);
> +      call_free_static_weak (__libc_getpwuid_freemem_ptr);
> +      call_free_static_weak (__libc_getspnam_freemem_ptr);
> +      call_free_static_weak (__libc_getaliasbyname_freemem_ptr);
> +      call_free_static_weak (__libc_gethostbyaddr_freemem_ptr);
> +      call_free_static_weak (__libc_gethostbyname_freemem_ptr);
> +      call_free_static_weak (__libc_gethostbyname2_freemem_ptr);
> +      call_free_static_weak (__libc_getnetbyaddr_freemem_ptr);
> +      call_free_static_weak (__libc_getnetbyname_freemem_ptr);
> +      call_free_static_weak (__libc_getprotobynumber_freemem_ptr);
> +      call_free_static_weak (__libc_getprotobyname_freemem_ptr);
> +      call_free_static_weak (__libc_getrpcbyname_freemem_ptr);
> +      call_free_static_weak (__libc_getrpcbynumber_freemem_ptr);
> +      call_free_static_weak (__libc_getservbyname_freemem_ptr);
> +      call_free_static_weak (__libc_getservbyport_freemem_ptr);
> +
> +      call_free_static_weak (__libc_getgrent_freemem_ptr);
> +      call_free_static_weak (__libc_getpwent_freemem_ptr);
> +      call_free_static_weak (__libc_getspent_freemem_ptr);
> +      call_free_static_weak (__libc_getaliasent_freemem_ptr);
> +      call_free_static_weak (__libc_gethostent_freemem_ptr);
> +      call_free_static_weak (__libc_getnetent_freemem_ptr);
> +      call_free_static_weak (__libc_getprotoent_freemem_ptr);
> +      call_free_static_weak (__libc_getrpcent_freemem_ptr);
> +      call_free_static_weak (__libc_getservent_freemem_ptr);
> +
> +      call_free_static_weak (__libc_efgcvt_freemem_ptr);
> +      call_free_static_weak (__libc_qefgcvt_freemem_ptr);

OK.

> +
> +      call_freeres_system_funcs;
>      }
>  }
>  libc_hidden_def (__libc_freeres)
> diff --git a/malloc/thread-freeres.c b/malloc/thread-freeres.c
> index b22e1d789f..a4fbc890b3 100644
> --- a/malloc/thread-freeres.c
> +++ b/malloc/thread-freeres.c
> @@ -16,18 +16,15 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> -#include <dlfcn/dlerror.h>
>  #include <libc-internal.h>
>  #include <malloc-internal.h>
> -#include <resolv/resolv-internal.h>
> -#include <rpc/rpc.h>
> -#include <string.h>
> -#include <tls-internal.h>
> +#include <set-freeres.h>
>  #include <shlib-compat.h>
> +#include <tls-internal.h>
>  
>  /* Thread shutdown function.  Note that this function must be called
>     for threads during shutdown for correctness reasons.  Unlike
> -   __libc_subfreeres, skipping calls to it is not a valid optimization.
> +   __libc_freeres, skipping calls to it is not a valid optimization.
>     This is called directly from pthread_create as the thread exits.  */
>  void
>  __libc_thread_freeres (void)
> diff --git a/misc/efgcvt-template.c b/misc/efgcvt-template.c
> index 87a90e78d4..816a13701d 100644
> --- a/misc/efgcvt-template.c
> +++ b/misc/efgcvt-template.c
> @@ -22,6 +22,7 @@
>  #include <sys/param.h>
>  #include <libc-lock.h>
>  #include <math_ldbl_opt.h>
> +#include <set-freeres.h>
>  
>  #ifndef SPRINTF
>  # define SPRINTF sprintf
> @@ -38,7 +39,7 @@
>  
>  static char FCVT_BUFFER[MAXDIG];
>  static char ECVT_BUFFER[MAXDIG];
> -libc_freeres_ptr (static char *FCVT_BUFPTR);
> +static char *FCVT_BUFPTR;
>  
>  char *
>  __FCVT (FLOAT_TYPE value, int ndigit, int *decpt, int *sign)
> @@ -73,3 +74,5 @@ __GCVT (FLOAT_TYPE value, int ndigit, char *buf)
>    SPRINTF (buf, "%.*" FLOAT_FMT_FLAG "g", MIN (ndigit, NDIGIT_MAX), value);
>    return buf;
>  }
> +
> +weak_alias (FCVT_BUFPTR, __EFGCVT_FREEMEM_PTR);
> diff --git a/misc/efgcvt.c b/misc/efgcvt.c
> index 95f1443d60..e9a866ef19 100644
> --- a/misc/efgcvt.c
> +++ b/misc/efgcvt.c
> @@ -24,6 +24,7 @@
>  #define __GCVT __gcvt
>  #define __ECVT_R __ecvt_r
>  #define __FCVT_R __fcvt_r
> +#define __EFGCVT_FREEMEM_PTR __libc_efgcvt_freemem_ptr
>  #include <efgcvt-dbl-macros.h>
>  #include <efgcvt-template.c>
>  
> diff --git a/misc/fstab.c b/misc/fstab.c
> index 952f7adc36..f55657ee17 100644
> --- a/misc/fstab.c
> +++ b/misc/fstab.c
> @@ -177,7 +177,8 @@ fstab_convert (struct fstab_state *state)
>  
>  /* Make sure the memory is freed if the programs ends while in
>     memory-debugging mode and something actually was allocated.  */
> -libc_freeres_fn (fstab_free)
> +void
> +__libc_fstab_freemem (void)
>  {
>    char *buffer;
>  
> diff --git a/misc/hsearch.c b/misc/hsearch.c
> index 3b7be37f81..37994b053e 100644
> --- a/misc/hsearch.c
> +++ b/misc/hsearch.c
> @@ -46,7 +46,3 @@ __hdestroy (void)
>    __hdestroy_r (&htab);
>  }
>  weak_alias (__hdestroy, hdestroy)
> -
> -/* Make sure the table is freed if we want to free everything before
> -   exiting.  */
> -text_set_element (__libc_subfreeres, __hdestroy);
> diff --git a/misc/mntent.c b/misc/mntent.c
> index 44e54df669..7511384c85 100644
> --- a/misc/mntent.c
> +++ b/misc/mntent.c
> @@ -19,6 +19,7 @@
>  #include <mntent.h>
>  #include <stdlib.h>
>  #include <allocate_once.h>
> +#include <set-freeres.h>
>  
>  struct mntent_buffer
>  {
> @@ -28,7 +29,7 @@ struct mntent_buffer
>  
>  /* We don't want to allocate the static buffer all the time since it
>     is not always used (in fact, rather infrequently).  */
> -libc_freeres_ptr (static void *mntent_buffer);
> +static void *mntent_buffer;
>  
>  static void *
>  allocate (void *closure)
> @@ -56,3 +57,5 @@ getmntent (FILE *stream)
>    return __getmntent_r (stream, &buffer->m,
>  			buffer->buffer, sizeof (buffer->buffer));
>  }
> +
> +weak_alias (mntent_buffer, __libc_mntent_freemem_ptr)
> diff --git a/misc/qefgcvt.c b/misc/qefgcvt.c
> index f48e0b6016..0773987e63 100644
> --- a/misc/qefgcvt.c
> +++ b/misc/qefgcvt.c
> @@ -24,6 +24,7 @@
>  #define __GCVT __qgcvt
>  #define __ECVT_R __qecvt_r
>  #define __FCVT_R __qfcvt_r
> +#define __EFGCVT_FREEMEM_PTR __libc_qefgcvt_freemem_ptr
>  #include <efgcvt-ldbl-macros.h>
>  #include <efgcvt-template.c>
>  
> diff --git a/misc/unwind-link.c b/misc/unwind-link.c
> index e8653bbaf1..0e01eed7fc 100644
> --- a/misc/unwind-link.c
> +++ b/misc/unwind-link.c
> @@ -131,7 +131,7 @@ __libc_unwind_link_after_fork (void)
>      }
>  }
>  
> -void __libc_freeres_fn_section
> +void
>  __libc_unwind_link_freeres (void)
>  {
>    if (global_libgcc_handle != NULL)
> diff --git a/nptl/nptlfreeres.c b/nptl/nptlfreeres.c
> index c67456d9d3..90b7b13287 100644
> --- a/nptl/nptlfreeres.c
> +++ b/nptl/nptlfreeres.c
> @@ -16,7 +16,6 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> -#include <set-hooks.h>
>  #include <libc-symbols.h>
>  #include <pthreadP.h>
>  #include <nptl-stack.h>
> diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
> index bde3b588a0..5afa258c19 100644
> --- a/nscd/nscd_getgr_r.c
> +++ b/nscd/nscd_getgr_r.c
> @@ -68,7 +68,8 @@ libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
>  /* Note that we only free the structure if necessary.  The memory
>     mapping is not removed since it is not visible to the malloc
>     handling.  */
> -libc_freeres_fn (gr_map_free)
> +void
> +__nscd_gr_map_freemem (void)
>  {
>    if (__gr_map_handle.mapped != NO_MAPPING)
>      {
> diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
> index 5958f181db..5b10771167 100644
> --- a/nscd/nscd_gethst_r.c
> +++ b/nscd/nscd_gethst_r.c
> @@ -81,7 +81,8 @@ libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
>  /* Note that we only free the structure if necessary.  The memory
>     mapping is not removed since it is not visible to the malloc
>     handling.  */
> -libc_freeres_fn (hst_map_free)
> +void
> +__nscd_hst_map_freemem (void)
>  {
>    if (__hst_map_handle.mapped != NO_MAPPING)
>      {
> diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
> index 82fdd17d8c..52256b58c4 100644
> --- a/nscd/nscd_getpw_r.c
> +++ b/nscd/nscd_getpw_r.c
> @@ -67,7 +67,8 @@ libc_locked_map_ptr (static, map_handle);
>  /* Note that we only free the structure if necessary.  The memory
>     mapping is not removed since it is not visible to the malloc
>     handling.  */
> -libc_freeres_fn (pw_map_free)
> +void
> +__nscd_pw_map_freemem (void)
>  {
>    if (map_handle.mapped != NO_MAPPING)
>      {
> diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
> index de843b3363..92c80fe8fe 100644
> --- a/nscd/nscd_getserv_r.c
> +++ b/nscd/nscd_getserv_r.c
> @@ -62,7 +62,8 @@ libc_locked_map_ptr (, __serv_map_handle) attribute_hidden;
>  /* Note that we only free the structure if necessary.  The memory
>     mapping is not removed since it is not visible to the malloc
>     handling.  */
> -libc_freeres_fn (serv_map_free)
> +void
> +__nscd_serv_map_freemem (void)
>  {
>    if (__serv_map_handle.mapped != NO_MAPPING)
>      {
> diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
> index 11b7f3214c..33c0096f86 100644
> --- a/nscd/nscd_netgroup.c
> +++ b/nscd/nscd_netgroup.c
> @@ -31,7 +31,8 @@ libc_locked_map_ptr (static, map_handle);
>  /* Note that we only free the structure if necessary.  The memory
>     mapping is not removed since it is not visible to the malloc
>     handling.  */
> -libc_freeres_fn (pw_map_free)
> +void
> +__nscd_group_map_freemem (void)
>  {
>    if (map_handle.mapped != NO_MAPPING)
>      {
> diff --git a/nss/getXXbyYY.c b/nss/getXXbyYY.c
> index 35a3a81e2b..522030bddd 100644
> --- a/nss/getXXbyYY.c
> +++ b/nss/getXXbyYY.c
> @@ -20,6 +20,7 @@
>  #include <libc-lock.h>
>  #include <stdlib.h>
>  #include <resolv.h>
> +#include <set-freeres.h>
>  
>  #include "nsswitch.h"
>  
> @@ -58,6 +59,9 @@
>  #define APPEND_R1(name) name##_r
>  #define INTERNAL(name) INTERNAL1 (name)
>  #define INTERNAL1(name) __##name
> +#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem_ptr
> +#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
> +#define FREEMEM_NAME APPEND_FREEMEM_NAME (FUNCTION_NAME)
>  
>  /* Sometimes we need to store error codes in the `h_errno' variable.  */
>  #ifdef NEED_H_ERRNO
> @@ -86,8 +90,9 @@ extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf,
>  __libc_lock_define_initialized (static, lock);
>  
>  /* This points to the static buffer used.  */
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
> +weak_alias (buffer, FREEMEM_NAME)
>  
>  LOOKUP_TYPE *
>  FUNCTION_NAME (ADD_PARAMS)
> diff --git a/nss/getXXent.c b/nss/getXXent.c
> index 35720a05dd..ea3ca918b0 100644
> --- a/nss/getXXent.c
> +++ b/nss/getXXent.c
> @@ -18,6 +18,7 @@
>  #include <errno.h>
>  #include <libc-lock.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  #include "nsswitch.h"
>  
> @@ -43,6 +44,9 @@
>  #define APPEND_R1(name) name##_r
>  #define INTERNAL(name) INTERNAL1 (name)
>  #define INTERNAL1(name) __##name
> +#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem_ptr
> +#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
> +#define FREEMEM_NAME APPEND_FREEMEM_NAME (GETFUNC_NAME)
>  
>  /* Sometimes we need to store error codes in the `h_errno' variable.  */
>  #ifdef NEED_H_ERRNO
> @@ -62,8 +66,9 @@ extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer,
>  __libc_lock_define_initialized (static, lock);
>  
>  /* This points to the static buffer used.  */
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
> +weak_alias (buffer, FREEMEM_NAME)
>  
>  LOOKUP_TYPE *
>  GETFUNC_NAME (void)
> diff --git a/nss/nss_action.c b/nss/nss_action.c
> index babea4e735..893880790f 100644
> --- a/nss/nss_action.c
> +++ b/nss/nss_action.c
> @@ -102,7 +102,7 @@ __nss_action_allocate (struct nss_action *actions, size_t count)
>    return result;
>  }
>  
> -void __libc_freeres_fn_section
> +void
>  __nss_action_freeres (void)
>  {
>    struct nss_action_list_wrapper *current = nss_actions;
> diff --git a/nss/nss_action.h b/nss/nss_action.h
> index 54c397c12f..d3da4f6617 100644
> --- a/nss/nss_action.h
> +++ b/nss/nss_action.h
> @@ -101,8 +101,5 @@ nss_action_list __nss_action_allocate (struct nss_action *actions,
>     EINVAL means that LINE is syntactically invalid.  */
>  nss_action_list __nss_action_parse (const char *line);
>  
> -/* Called from __libc_freeres.  */
> -void __nss_action_freeres (void) attribute_hidden;
> -
>  
>  #endif /* _NSS_ACTION_H */
> diff --git a/nss/nss_database.c b/nss/nss_database.c
> index f2ed2f2c25..7e5b7f362b 100644
> --- a/nss/nss_database.c
> +++ b/nss/nss_database.c
> @@ -495,7 +495,7 @@ __nss_database_get_noreload (enum nss_database db)
>    return result;
>  }
>  
> -void __libc_freeres_fn_section
> +void
>  __nss_database_freeres (void)
>  {
>    free (global_database_state);
> diff --git a/nss/nss_database.h b/nss/nss_database.h
> index c28d6a861d..92ef189453 100644
> --- a/nss/nss_database.h
> +++ b/nss/nss_database.h
> @@ -64,9 +64,6 @@ libc_hidden_proto (__nss_database_get)
>  nss_action_list __nss_database_get_noreload (enum nss_database db)
>    attribute_hidden;
>  
> -/* Called from __libc_freeres.  */
> -void __nss_database_freeres (void) attribute_hidden;
> -
>  /* Internal type.  Exposed only for fork handling purposes.  */
>  struct nss_database_data
>  {
> diff --git a/nss/nss_module.c b/nss/nss_module.c
> index 444facb9b8..ed224018b1 100644
> --- a/nss/nss_module.c
> +++ b/nss/nss_module.c
> @@ -416,7 +416,7 @@ __nss_module_disable_loading (void)
>    __libc_lock_unlock (nss_module_list_lock);
>  }
>  
> -void __libc_freeres_fn_section
> +void
>  __nss_module_freeres (void)
>  {
>    struct nss_module *current = nss_module_list;
> diff --git a/nss/nss_module.h b/nss/nss_module.h
> index b0eb067f2a..8cb76f1950 100644
> --- a/nss/nss_module.h
> +++ b/nss/nss_module.h
> @@ -100,7 +100,4 @@ void *__nss_module_get_function (struct nss_module *module, const char *name)
>  /* Block attempts to dlopen any module we haven't already opened.  */
>  void __nss_module_disable_loading (void);
>  
> -/* Called from __libc_freeres.  */
> -void __nss_module_freeres (void) attribute_hidden;
> -
>  #endif /* NSS_MODULE_H */
> diff --git a/posix/regcomp.c b/posix/regcomp.c
> index 84fc1cc82b..634dccf03f 100644
> --- a/posix/regcomp.c
> +++ b/posix/regcomp.c
> @@ -710,7 +710,8 @@ re_comp (const char *s)
>  }
>  
>  #ifdef _LIBC
> -libc_freeres_fn (free_mem)
> +void
> +__libc_regcomp_freemem (void)
>  {
>    __regfree (&re_comp_buf);
>  }
> diff --git a/posix/register-atfork.c b/posix/register-atfork.c
> index c039fb454f..d386731b92 100644
> --- a/posix/register-atfork.c
> +++ b/posix/register-atfork.c
> @@ -217,7 +217,8 @@ __run_postfork_handlers (enum __run_fork_handler_type who, _Bool do_locking,
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__libc_atfork_freemem (void)
>  {
>    lll_lock (atfork_lock, LLL_PRIVATE);
>  
> diff --git a/pwd/fgetpwent.c b/pwd/fgetpwent.c
> index 1ddc98a0d0..806416d761 100644
> --- a/pwd/fgetpwent.c
> +++ b/pwd/fgetpwent.c
> @@ -20,12 +20,13 @@
>  #include <pwd.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one entry from the given stream.  */
>  struct passwd *
> @@ -82,3 +83,5 @@ fgetpwent (FILE *stream)
>  
>    return result;
>  }
> +
> +weak_alias (buffer, __libc_fgetpwent_freemem_ptr)
> diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c
> index 8ce3c778eb..b6fcd0f301 100644
> --- a/resolv/gai_misc.c
> +++ b/resolv/gai_misc.c
> @@ -434,7 +434,11 @@ handle_requests (void *arg)
>  
>  
>  /* Free allocated resources.  */
> -libc_freeres_fn (free_res)
> +#if !PTHREAD_IN_LIBC
> +__attribute__ ((__destructor__)) static
> +#endif
> +void
> +__gai_freemem (void)
>  {
>    size_t row;
>  
> diff --git a/resolv/res-close.c b/resolv/res-close.c
> index dd116ea5c0..55e49b6db0 100644
> --- a/resolv/res-close.c
> +++ b/resolv/res-close.c
> @@ -140,5 +140,3 @@ __res_thread_freeres (void)
>    /* Make sure we do a full re-initialization the next time.  */
>    _res.options = 0;
>  }
> -/* Also must be called when the main thread exits.  */
> -text_set_element (__libc_subfreeres, __res_thread_freeres);
> diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c
> index dd09a2a255..5a995e74c1 100644
> --- a/resolv/res_hconf.c
> +++ b/resolv/res_hconf.c
> @@ -42,6 +42,7 @@
>  #include "res_hconf.h"
>  #include <wchar.h>
>  #include <atomic.h>
> +#include <set-freeres.h>
>  
>  #if IS_IN (libc)
>  # define fgets_unlocked __fgets_unlocked
> @@ -330,19 +331,8 @@ _res_hconf_init (void)
>  #if IS_IN (libc)
>  # if defined SIOCGIFCONF && defined SIOCGIFNETMASK
>  /* List of known interfaces.  */
> -libc_freeres_ptr (
> -static struct netaddr
> -{
> -  int addrtype;
> -  union
> -  {
> -    struct
> -    {
> -      uint32_t	addr;
> -      uint32_t	mask;
> -    } ipv4;
> -  } u;
> -} *ifaddrs);
> +static struct netaddr *ifaddrs;
> +weak_alias (ifaddrs, __libc_resolv_res_hconf_freemem_ptr)
>  # endif
>  
>  /* Reorder addresses returned in a hostent such that the first address
> diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
> index bb12f474d2..d47004a780 100644
> --- a/resolv/resolv-internal.h
> +++ b/resolv/resolv-internal.h
> @@ -34,6 +34,20 @@
>     loads and stores.  */
>  typedef HEADER __attribute__ ((__aligned__(1))) UHEADER;
>  
> +/* List of known interfaces.  */
> +struct netaddr
> +{
> +  int addrtype;
> +  union
> +  {
> +    struct
> +    {
> +      uint32_t	addr;
> +      uint32_t	mask;
> +    } ipv4;
> +  } u;
> +};
> +
>  /* Legacy function.  This needs to be removed once all NSS modules
>     have been adjusted.  */
>  static inline bool
> diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
> index 6dd552bb47..2fb6b36839 100644
> --- a/resolv/resolv_conf.c
> +++ b/resolv/resolv_conf.c
> @@ -654,7 +654,8 @@ __resolv_conf_detach (struct __res_state *resp)
>  }
>  
>  /* Deallocate the global data.  */
> -libc_freeres_fn (freeres)
> +void
> +__libc_resolv_conf_freemem (void)
>  {
>    /* No locking because this function is supposed to be called when
>       the process has turned single-threaded.  */
> diff --git a/resolv/tst-leaks2.c b/resolv/tst-leaks2.c
> index 160d4728d5..48d643dcde 100644
> --- a/resolv/tst-leaks2.c
> +++ b/resolv/tst-leaks2.c
> @@ -23,6 +23,8 @@
>  #include <resolv.h>
>  #include <support/check.h>
>  
> +void __libc_freeres (void);
> +
>  static int
>  do_test (void)
>  {
> diff --git a/rt/aio_misc.c b/rt/aio_misc.c
> index b4304d0a6f..2e62e80de2 100644
> --- a/rt/aio_misc.c
> +++ b/rt/aio_misc.c
> @@ -694,7 +694,11 @@ handle_fildes_io (void *arg)
>  
>  
>  /* Free allocated resources.  */
> -libc_freeres_fn (free_res)
> +#if !PTHREAD_IN_LIBC
> +__attribute__ ((__destructor__)) static
> +#endif
> +void
> +__aio_freemem (void)
>  {
>    size_t row;
>  
> diff --git a/shadow/fgetspent.c b/shadow/fgetspent.c
> index 5f75e31c29..63b52c40be 100644
> --- a/shadow/fgetspent.c
> +++ b/shadow/fgetspent.c
> @@ -20,6 +20,7 @@
>  #include <shadow.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  
>  /* A reasonable size for a buffer to start with.  */
> @@ -28,7 +29,7 @@
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one shadow entry from the given stream.  */
>  struct spwd *
> @@ -85,3 +86,5 @@ fgetspent (FILE *stream)
>  
>    return result;
>  }
> +
> +weak_alias (buffer, __libc_fgetspent_freemem_ptr);
> diff --git a/stdio-common/reg-modifier.c b/stdio-common/reg-modifier.c
> index fa1cd2ac3c..b8232b5ff8 100644
> --- a/stdio-common/reg-modifier.c
> +++ b/stdio-common/reg-modifier.c
> @@ -183,7 +183,8 @@ __handle_registered_modifier_wc (const unsigned int **format,
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__libc_printf_freemem (void)
>  {
>    if (__printf_modifier_table != NULL)
>      {
> diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c
> index 5f4c6a24c2..a9b6cbbb40 100644
> --- a/stdio-common/reg-printf.c
> +++ b/stdio-common/reg-printf.c
> @@ -21,11 +21,11 @@
>  #include <stddef.h>
>  #include <stdlib.h>
>  #include <libc-lock.h>
> +#include <set-freeres.h>
>  
>  
>  /* Array of functions indexed by format character.  */
> -libc_freeres_ptr (printf_arginfo_size_function **__printf_arginfo_table)
> -  attribute_hidden;
> +printf_arginfo_size_function **__printf_arginfo_table attribute_hidden;
>  printf_function **__printf_function_table attribute_hidden;
>  
>  __libc_lock_define_initialized (static, lock)
> @@ -79,3 +79,5 @@ __register_printf_function (int spec, printf_function converter,
>  				      (printf_arginfo_size_function*) arginfo);
>  }
>  weak_alias (__register_printf_function, register_printf_function)
> +
> +weak_alias (__printf_arginfo_table, __libc_reg_printf_freemem_ptr)
> diff --git a/stdio-common/reg-type.c b/stdio-common/reg-type.c
> index f308db6323..2d4f412fa5 100644
> --- a/stdio-common/reg-type.c
> +++ b/stdio-common/reg-type.c
> @@ -19,11 +19,11 @@
>  #include <printf.h>
>  #include <stdlib.h>
>  #include <libc-lock.h>
> +#include <set-freeres.h>
>  
>  
>  /* Array of functions indexed by format character.  */
> -libc_freeres_ptr (printf_va_arg_function **__printf_va_arg_table)
> -  attribute_hidden;
> +printf_va_arg_function **__printf_va_arg_table attribute_hidden;
>  
>  __libc_lock_define_initialized (static, lock);
>  
> @@ -59,3 +59,5 @@ __register_printf_type (printf_va_arg_function fct)
>    return result;
>  }
>  weak_alias (__register_printf_type, register_printf_type)
> +
> +weak_alias (__printf_va_arg_table, __libc_reg_type_freemem_ptr)
> diff --git a/stdlib/exit.c b/stdlib/exit.c
> index 98579fbda8..392b37259b 100644
> --- a/stdlib/exit.c
> +++ b/stdlib/exit.c
> @@ -20,7 +20,7 @@
>  #include <unistd.h>
>  #include <pointer_guard.h>
>  #include <libc-lock.h>
> -#include <libio/libioP.h>
> +#include <set-freeres.h>
>  #include "exit.h"
>  
>  /* Initialize the flag that indicates exit function processing
> diff --git a/stdlib/fmtmsg.c b/stdlib/fmtmsg.c
> index 787a263d63..7561a2936b 100644
> --- a/stdlib/fmtmsg.c
> +++ b/stdlib/fmtmsg.c
> @@ -361,7 +361,8 @@ __addseverity (int severity, const char *string)
>  weak_alias (__addseverity, addseverity)
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__libc_fmtmsg_freemem (void)
>  {
>    struct severity_info *runp = severity_list;
>  
> diff --git a/stdlib/setenv.c b/stdlib/setenv.c
> index 2176cbac31..e44d41019c 100644
> --- a/stdlib/setenv.c
> +++ b/stdlib/setenv.c
> @@ -323,7 +323,8 @@ clearenv (void)
>    return 0;
>  }
>  #ifdef _LIBC
> -libc_freeres_fn (free_mem)
> +void
> +__libc_setenv_freemem (void)
>  {
>    /* Remove all traces.  */
>    clearenv ();
> diff --git a/sunrpc/clnt_perr.c b/sunrpc/clnt_perr.c
> index 67499fd03f..c3d13722df 100644
> --- a/sunrpc/clnt_perr.c
> +++ b/sunrpc/clnt_perr.c
> @@ -389,8 +389,8 @@ auth_errmsg (enum auth_stat stat)
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__rpc_freemem (void)
>  {
> -  /* Not libc_freeres_ptr, since buf is a macro.  */
>    free (buf);
>  }
> diff --git a/sunrpc/rpc_thread.c b/sunrpc/rpc_thread.c
> index 0abe6dc172..a04b7ec47f 100644
> --- a/sunrpc/rpc_thread.c
> +++ b/sunrpc/rpc_thread.c
> @@ -37,7 +37,6 @@ __rpc_thread_destroy (void)
>  		thread_rpc_vars = NULL;
>  	}
>  }
> -text_set_element (__libc_subfreeres, __rpc_thread_destroy);
>  
>  /*
>   * Initialize RPC multi-threaded operation
> diff --git a/sunrpc/tst-svc_register.c b/sunrpc/tst-svc_register.c
> index 41c5398ab6..4f3c31c504 100644
> --- a/sunrpc/tst-svc_register.c
> +++ b/sunrpc/tst-svc_register.c
> @@ -276,9 +276,9 @@ do_test (void)
>                else
>                  /* This is arguably a bug: Regular process termination
>                     does not unregister the service with rpcbind.  The
> -                   unset rpcbind call happens from a __libc_subfreeres
> -                   callback, and this only happens when running under
> -                   memory debuggers such as valgrind.  */
> +                   unset rpcbind call happens from a __libc_freeres,
> +                   and this only happens when running under memory debuggers
> +		   such as valgrind.  */
>                  TEST_VERIFY (!state.unset_called);
>              }
>            else
> diff --git a/sysdeps/generic/set-freeres-fp.h b/sysdeps/generic/set-freeres-fp.h
> new file mode 100644
> index 0000000000..f73ac747ad
> --- /dev/null
> +++ b/sysdeps/generic/set-freeres-fp.h
> @@ -0,0 +1,19 @@
> +/* System specific resource deallocation.  Generic version.
> +   Copyright (C) 2022 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/>.  */
> +
> +#define call_freeres_fp_funcs
> diff --git a/sysdeps/generic/set-freeres-os.h b/sysdeps/generic/set-freeres-os.h
> new file mode 100644
> index 0000000000..6b17c8307a
> --- /dev/null
> +++ b/sysdeps/generic/set-freeres-os.h
> @@ -0,0 +1,19 @@
> +/* System specific resource deallocation.  Generic version.
> +   Copyright (C) 2020-2022 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/>.  */
> +
> +#define call_freeres_os_funcs
> diff --git a/sysdeps/generic/set-freeres-system.h b/sysdeps/generic/set-freeres-system.h
> new file mode 100644
> index 0000000000..88701a657f
> --- /dev/null
> +++ b/sysdeps/generic/set-freeres-system.h

OK. Put this in a distinct header.

> @@ -0,0 +1,27 @@
> +/* System specific resource deallocation.  Generic version.
> +   Copyright (C) 2022 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/>.  */
> +
> +/* Each system may define weak functions to free any resource allocated with
> +   malloc to avoid interfere with mtrace.  */
> +
> +#include <set-freeres-os.h>
> +#include <set-freeres-fp.h>
> +
> +#define call_freeres_system_funcs	\
> +  call_freeres_os_funcs;		\
> +  call_freeres_fp_funcs
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
> index 9703069b95..ad83f5d8f3 100644
> --- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
> @@ -42,6 +42,7 @@ typeof (qfcvt_r) ___qfcvtieee128_r;
>  #define __GCVT ___qgcvtieee128
>  #define __ECVT_R ___qecvtieee128_r
>  #define __FCVT_R ___qfcvtieee128_r
> +#define __EFGCVT_FREEMEM_PTR __libc_efgcvtieee128_freemem_ptr
>  #include <efgcvt-ldbl-macros.h>
>  #include <efgcvt-template.c>
>  
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h b/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
> new file mode 100644
> index 0000000000..3f6e17612a
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
> @@ -0,0 +1,22 @@
> +/* System specific resource deallocation.  IBM long double 128 version.
> +   Copyright (C) 2022 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/>.  */
> +
> +extern char * __libc_efgcvtieee128_freemem_ptr attribute_hidden;
> +
> +#define call_freeres_fp_funcs \
> +  call_free_static_weak (__libc_efgcvtieee128_freemem_ptr)
> diff --git a/sysdeps/mach/hurd/bits/errno.h b/sysdeps/mach/hurd/bits/errno.h
> index 90c8897739..0d935e724a 100644
> --- a/sysdeps/mach/hurd/bits/errno.h
> +++ b/sysdeps/mach/hurd/bits/errno.h
> @@ -9,7 +9,6 @@
>       mach/boolean.h
>       mach/i386/boolean.h
>       mach/i386/vm_types.h
> -     mach/i386/stdint.h
>       mach/mig_errors.h
>       device/device_types.h
>       mach/std_types.h
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index 5cda9bb072..bdc56d9781 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -1761,7 +1761,8 @@ check_gaiconf_mtime (const struct __stat64_t64 *st)
>  #endif
>  
>  
> -libc_freeres_fn(fini)
> +void
> +__libc_getaddrinfo_freemem (void)
>  {
>    if (labels != default_labels)
>      {
> @@ -2233,7 +2234,7 @@ no_file:
>  
>    /* If we previously read the file but it is gone now, free the old data and
>       use the builtin one.  Leave the reload flag alone.  */
> -  fini ();
> +  __libc_getaddrinfo_freemem ();
>  }
>  
>  
> diff --git a/sysdeps/posix/ttyname.c b/sysdeps/posix/ttyname.c
> index fd41f7fb24..db83b584af 100644
> --- a/sysdeps/posix/ttyname.c
> +++ b/sysdeps/posix/ttyname.c
> @@ -24,6 +24,7 @@
>  #include <unistd.h>
>  #include <string.h>
>  #include <stdlib.h>
> +#include <set-freeres.h>
>  
>  char *__ttyname;
>  
> @@ -31,7 +32,8 @@ static char *getttyname (int fd, dev_t mydev, ino_t myino,
>  			 int save, int *dostat);
>  
>  
> -libc_freeres_ptr (static char *getttyname_name);
> +static char *getttyname_name;
> +weak_alias (getttyname_name, __ttyname_freemem_ptr)
>  
>  static char *
>  getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat)
> diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
> index 0b77a2d897..bdda4e890d 100644
> --- a/sysdeps/unix/sysv/linux/check_pf.c
> +++ b/sysdeps/unix/sysv/linux/check_pf.c
> @@ -362,7 +362,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
>  }
>  
>  /* Free the cache if it has been allocated.  */
> -libc_freeres_fn (freecache)
> +void
> +__check_pf_freemem (void)
>  {
>    if (cache)
>      __free_in6ai (cache->in6ai);
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
> index 6f8a06a0c8..699cea5125 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
> @@ -25,6 +25,7 @@
>  # define weak_alias(n,a)
>  #endif
>  #include "login/getutent.c"
> +_weak_alias (buffer, __libc_getutent_freemem_ptr)
>  
>  #if defined SHARED
>  default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
> index 6114582ed3..1af1aea5ab 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
> @@ -25,6 +25,7 @@
>  # define weak_alias(n,a)
>  #endif
>  #include "login/getutid.c"
> +_weak_alias (buffer, __libc_getutid_freemem_ptr)
>  
>  #if defined SHARED
>  default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
> index 88ac71e1f4..7a49bcf9db 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
> @@ -25,6 +25,7 @@
>  # define weak_alias(n,a)
>  #endif
>  #include "login/getutline.c"
> +_weak_alias (buffer, __libc_getutline_freemem_ptr)
>  
>  #if defined SHARED
>  default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
> diff --git a/sysdeps/unix/sysv/linux/set-freeres-os.h b/sysdeps/unix/sysv/linux/set-freeres-os.h
> new file mode 100644
> index 0000000000..964c9a4bfc
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/set-freeres-os.h
> @@ -0,0 +1,24 @@
> +/* System specific resource deallocation.  Linux version.
> +   Copyright (C) 2022 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/>.  */
> +
> +extern void __check_pf_freemem (void) attribute_hidden;
> +extern char * __ttyname_freemem_ptr attribute_hidden;
> +
> +#define call_freeres_os_funcs			  \
> +  call_function_static_weak (__check_pf_freemem); \
> +  call_free_static_weak (__ttyname_freemem_ptr)
> diff --git a/sysdeps/unix/sysv/linux/ttyname.c b/sysdeps/unix/sysv/linux/ttyname.c
> index 947c1f72a1..3b6e7ee2f2 100644
> --- a/sysdeps/unix/sysv/linux/ttyname.c
> +++ b/sysdeps/unix/sysv/linux/ttyname.c
> @@ -19,15 +19,11 @@
>  #include <limits.h>
>  #include <termios.h>
>  #include <stdlib.h>
> -
> +#include <set-freeres.h>
>  #include "ttyname.h"
>  
>  static char *ttyname_buf = NULL;
> -
> -libc_freeres_fn (free_mem)
> -{
> -  free (ttyname_buf);
> -}
> +weak_alias (ttyname_buf, __ttyname_freemem_ptr)
>  
>  /* Return the pathname of the terminal FD is open on, or NULL on errors.
>     The returned storage is good only until the next call to this function.  */
> diff --git a/time/tzfile.c b/time/tzfile.c
> index 394b098856..f4f56e56ef 100644
> --- a/time/tzfile.c
> +++ b/time/tzfile.c
> @@ -26,6 +26,7 @@
>  #include <sys/stat.h>
>  #include <stdint.h>
>  #include <alloc_buffer.h>
> +#include <set-freeres.h>
>  
>  #include <timezone/tzfile.h>
>  
> @@ -50,7 +51,7 @@ struct leap
>    };
>  
>  static size_t num_transitions;
> -libc_freeres_ptr (static __time64_t *transitions);
> +static __time64_t *transitions;
>  static unsigned char *type_idxs;
>  static size_t num_types;
>  static struct ttinfo *types;
> @@ -777,3 +778,5 @@ __tzfile_compute (__time64_t timer, int use_localtime,
>  	}
>      }
>  }
> +
> +weak_alias (transitions, __libc_tzfile_freemem_ptr)
> diff --git a/time/tzset.c b/time/tzset.c
> index a06142bb58..b8b1ee2662 100644
> --- a/time/tzset.c
> +++ b/time/tzset.c
> @@ -610,7 +610,8 @@ __tz_convert (__time64_t timer, int use_localtime, struct tm *tp)
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void
> +__libc_tzset_freemem (void)
>  {
>    while (tzstring_list != NULL)
>      {

-- 
Cheers,
Carlos.


  reply	other threads:[~2023-03-04 17:37 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-27 21:11 [PATCH v3 0/4] Remove --with-default-link option Adhemerval Zanella
2022-12-27 21:11 ` [PATCH v3 1/4] Move libc_freeres_ptrs and libc_subfreeres to hidden/weak functions Adhemerval Zanella
2023-03-04 17:37   ` Carlos O'Donell [this message]
2022-12-27 21:11 ` [PATCH v3 2/4] libio: Remove the usage of __libc_IO_vtables Adhemerval Zanella
2023-03-04 17:37   ` Carlos O'Donell
2023-03-06 13:43     ` Adhemerval Zanella Netto
2023-03-27 12:53       ` Carlos O'Donell
2023-03-06 14:58   ` Arsen Arsenović
2023-03-06 16:01     ` Adhemerval Zanella Netto
2023-03-06 16:31       ` Andreas Schwab
2023-03-06 16:39         ` Adhemerval Zanella Netto
2023-03-06 16:53           ` Andreas Schwab
2023-03-06 17:24             ` Adhemerval Zanella Netto
2023-03-06 18:17               ` Adhemerval Zanella Netto
2023-03-06 18:47                 ` Arsen Arsenović
2023-03-06 18:53                   ` Adhemerval Zanella Netto
2023-03-06 19:10                     ` Arsen Arsenović
2023-03-06 19:20                       ` Adhemerval Zanella Netto
2023-03-06 19:26                         ` Arsen Arsenović
2023-03-06 16:23     ` Andreas Schwab
2022-12-27 21:11 ` [PATCH v3 3/4] Remove --with-default-link configure option Adhemerval Zanella
2023-03-04 17:39   ` Carlos O'Donell
2022-12-27 21:11 ` [PATCH v3 4/4] Remove set-hooks.h from generic includes Adhemerval Zanella
2023-03-04 17:42   ` Carlos O'Donell
2023-03-04 17:37 ` [PATCH v3 0/4] Remove --with-default-link option Carlos O'Donell
2023-03-06 13:43   ` Adhemerval Zanella Netto

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=35cd3223-8766-3b6f-2126-ea99d90ec1cb@redhat.com \
    --to=carlos@redhat.com \
    --cc=adhemerval.zanella@linaro.org \
    --cc=fweimer@redhat.com \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).