diff --git a/ChangeLog b/ChangeLog
index 72badfe3f5..1320c23455 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,62 @@
+2018-06-26  DJ Delorie  <dj@redhat.com>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #23329]
+	* include/libc-symbols: Comment the freeres framework.
+	(__libc_freeres_fn_section): Define.
+	(__libc_thread_freeres_fn_section): Define.
+	(__libdl_freeres_fn_section): Define.
+	(__libthread_freeres_fn_section): Define.
+	(libc_thread_freeres_fn): Define.
+	* dlfcn/Makefile (libdl-routines): Add dlfreeres.
+	* dlfcn/Versions (GLIBC_PRIVATE): Add __libdl_freeres.
+	* dlfcn/dlerror.c: Include libc-symbols.h
+	(__dlerror_main_freeres): New function.
+	* include/dlfcn.h: Declare __dlerror_main_freeres.
+	* dlfcn/dlfreeres.c: New file.
+	* dlfcn/sdlfreeres.c: New file.
+	* include/set-hooks.h: Include libc-symbols.h.  Fix comment.
+	* malloc/arena.c: Include libc-symbols.h.
+	(arena_thread_freeres): Use __libc_thread_freeres_fn_section.
+	* malloc/set-freeres.c: Add hook for libdl.so, and libpthread.so.
+	(__libc_subfreeres): Call libdl and libpthread hooks.
+	* malloc/thread-freeres.c: Add comments.  Use
+	__libc_thread_freeres_fn_section.
+	* nptl/Makefile (libpthread-routines): Add nptlfreeres.
+	* nptl/Version (GLIBC_PRIVATE): Add __libpthread_freeres.
+	* nptl/allocatestack.c (__nptl_free_stacks): New function.
+	(__free_stacks): Rename to...
+	(free_stacks): ...this. Mark static.
+	(queue_stack): Call free_stacks.
+	* nptl/libc_pthread_init.c (freeres_libpthread): Delete.
+	* sysdeps/nptl/pthread-functions.h (pthread_functions): Remove
+	ptr_freeres.
+	* nptl/nptl-init.c (pthread_functions): Remove nptl_freeres.
+	(nptl_freeres): Remove.
+	* nptl/nptlfreeres.c: New file.
+	* nptl/pthreadP.h
+	[IS_IN (libpthread) && SHARED ] (__unwind_freeres): Rename to...
+	[IS_IN (libpthread)] (__nptl_unwind_freeres): ...this.
+	(__free_stacks): Rename to...
+	(__nptl_free_stacks): ...this.
+	(__freeres_shm_directory): Declare.
+	* nptl/unwind-forcedunwind.c: Include libc-symbols.h.
+	(__unwind_freeres): Rename to...
+	(__nptl_unwind_freeres): ...this.  Use libpthread_freeres_fn.
+	* sysdeps/unix/sysv/linux/shm-directory.c (freeit): Rename to...
+	[IS_IN (libpthread)] (__freeres_shm_directory): ...this.
+	Use libpthread_freeres_fn.
+	* resolv/res-close.c: Include libc-symbols.h.
+	(res_thread_freeres): Use __libc_thread_freeres_fn_section.
+	* resolv/resolv_conf.c: Include libc-symbols.h.
+	(freeres): Use libc_freeres_fn.
+	* string/strerror_l.c: Include libc-symbols.h.
+	(strerror_thread_freeres): Use __libc_thread_freeres_fn_section.
+	* sunrpc/rpc_thread.c: Include libc-symbols.h.
+	(__rpc_thread_destroy): Use __libc_thread_freeres_fn_section.
+	* sysdeps/mach/strerror_l.c: Inlcude libc-symbols.h
+	(strerror_thread_freeres): Use __libc_thread_freeres_fn_section.
+
 2018-06-26  Joseph Myers  <joseph@codesourcery.com>
 
 	[BZ #13888]
diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index 56dcae0604..34f9923334 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -22,7 +22,7 @@ include ../Makeconfig
 headers		:= bits/dlfcn.h dlfcn.h
 extra-libs	:= libdl
 libdl-routines	:= dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
-		   dlmopen dlfcn
+		   dlmopen dlfcn dlfreeres
 routines	:= $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines)))
 elide-routines.os := $(routines)
 
diff --git a/dlfcn/Versions b/dlfcn/Versions
index 97902f0dfd..1df6925a92 100644
--- a/dlfcn/Versions
+++ b/dlfcn/Versions
@@ -13,5 +13,6 @@ libdl {
   }
   GLIBC_PRIVATE {
     _dlfcn_hook;
+    __libdl_freeres;
   }
 }
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 04dce9ddc6..1846c9a882 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <libc-lock.h>
 #include <ldsodefs.h>
+#include <libc-symbols.h>
 
 #if !defined SHARED && IS_IN (libdl)
 
@@ -222,6 +223,19 @@ free_key_mem (void *mem)
 
 # ifdef SHARED
 
+/* Free the dlerror-related resources.  */
+void __libdl_freeres_fn_section
+__dlerror_main_freeres (void)
+{
+  void *mem;
+  /* Free the global memory if used.  */
+  check_free (&last_result);
+  /* Free the TSD memory if used.  */
+  mem = __libc_getspecific (key);
+  if (mem != NULL)
+    free_key_mem (mem);
+}
+
 struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
 libdl_hidden_data_def (_dlfcn_hook)
 
diff --git a/dlfcn/dlfreeres.c b/dlfcn/dlfreeres.c
new file mode 100644
index 0000000000..17752efa73
--- /dev/null
+++ b/dlfcn/dlfreeres.c
@@ -0,0 +1,30 @@
+/* Clean up allocated libdl memory on demand.
+   Copyright (C) 2018 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <set-hooks.h>
+#include <libc-symbols.h>
+#include <dlfcn.h>
+
+/* Free libdl.so resources.
+   Note: Caller ensures we are called only once.  */
+void __libdl_freeres_fn_section
+__libdl_freeres (void)
+{
+  call_function_static_weak (__dlerror_main_freeres);
+}
+libc_hidden_def (__libdl_freeres)
diff --git a/dlfcn/sdlfreeres.c b/dlfcn/sdlfreeres.c
new file mode 100644
index 0000000000..7347672990
--- /dev/null
+++ b/dlfcn/sdlfreeres.c
@@ -0,0 +1 @@
+#include "dlfreeres.c"
diff --git a/include/dlfcn.h b/include/dlfcn.h
index c231309083..0dc57dbe22 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -155,6 +155,8 @@ extern void __libc_register_dl_open_hook (struct link_map *map)
 extern void __libc_register_dlfcn_hook (struct link_map *map)
      attribute_hidden;
 #endif
-#endif
 
+extern void __dlerror_main_freeres (void) attribute_hidden;
+
+#endif
 #endif
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index 6137304b0b..89a5604ee7 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -217,16 +217,6 @@
   static const char __evoke_link_warning_##symbol[]	\
     __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \
     = msg;
-#define libc_freeres_ptr(decl) \
-  __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
-  decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
-#define __libc_freeres_fn_section \
-  __attribute__ ((section ("__libc_freeres_fn")))
-
-#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)
 
 /* A canned warning for sysdeps/stub functions.  */
 #define	stub_warning(name) \
@@ -244,6 +234,105 @@ 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.
+
+	You should still place your function into the appropriate
+	section like this (such functions cannot be static and must be
+	prototyped in the appropriate headers):
+
+	foo.c:
+	void __libdl_freeres_fn_section
+	foo (void)
+	{
+	  free (mem);
+	}
+
+	This helps ensure we have some markup for the relevant functions
+	and that they do not pollute icache.  */
+
+/* Resource pointers to freed 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.  */
+#define __libc_freeres_fn_section \
+  __attribute__ ((section ("__libc_freeres_fn")))
+
+/* Resource freeing functions for threads in libc.so.  */
+#define __libc_thread_freeres_fn_section \
+  __attribute__ ((section ("__libc_thread_freeres_fn")))
+
+/* Resource freeing functions for libdl.so  */
+#define __libdl_freeres_fn_section \
+  __attribute__ ((section ("__libdl_freeres_fn")))
+
+/* Resource freeing functions for libpthread.so.  */
+#define __libpthread_freeres_fn_section \
+  __attribute__ ((section ("__libpthread_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)
+
 /* 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-hooks.h b/include/set-hooks.h
index 0207656bb9..b3bd8b4092 100644
--- a/include/set-hooks.h
+++ b/include/set-hooks.h
@@ -22,11 +22,12 @@
 #define __need_size_t
 #include <stddef.h>
 #include <sys/cdefs.h>
+#include <libc-symbols.h>
 
 #ifdef symbol_set_define
 /* Define a hook variable called NAME.  Functions put on this hook take
    arguments described by PROTO.  Use `text_set_element (NAME, FUNCTION)'
-   from gnu-stabs.h to add a function to the hook.  */
+   from include/libc-symbols.h to add a function to the hook.  */
 
 # define DEFINE_HOOK(NAME, PROTO)		\
   typedef void __##NAME##_hook_function_t PROTO; \
diff --git a/malloc/arena.c b/malloc/arena.c
index 497ae475e7..fa295e5dba 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -18,6 +18,7 @@
    not, see <http://www.gnu.org/licenses/>.  */
 
 #include <stdbool.h>
+#include <libc-symbols.h>
 
 #if HAVE_TUNABLES
 # define TUNABLE_NAMESPACE malloc
@@ -941,7 +942,7 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
   return ar_ptr;
 }
 
-void
+void __libc_thread_freeres_fn_section
 __malloc_arena_thread_freeres (void)
 {
   /* Shut down the thread cache first.  This could deallocate data for
diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index f4a0e7bda4..9e0de0c403 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -26,6 +26,10 @@ DEFINE_HOOK (__libc_subfreeres, (void));
 
 symbol_set_define (__libc_freeres_ptrs);
 
+extern __attribute__((weak)) void __libdl_freeres (void);
+
+extern __attribute__((weak)) void __libpthread_freeres (void);
+
 void __libc_freeres_fn_section
 __libc_freeres (void)
 {
@@ -39,8 +43,19 @@ __libc_freeres (void)
 
       _IO_cleanup ();
 
+      /* We run the resource freeing after IO cleanup.  */
       RUN_HOOK (__libc_subfreeres, ());
 
+      /* Call the libdl list of cleanup functions
+	 (weak-ref-and-check).  */
+      if (&__libdl_freeres != NULL)
+	call_function_static_weak (__libdl_freeres);
+
+      /* Call the libpthread list of cleanup functions
+	 (weak-ref-and-check).  */
+      if (&__libpthread_freeres != NULL)
+	call_function_static_weak (__libpthread_freeres);
+
       for (p = symbol_set_first_element (__libc_freeres_ptrs);
            !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
         free (*p);
diff --git a/malloc/thread-freeres.c b/malloc/thread-freeres.c
index 8902c845bc..99eda83822 100644
--- a/malloc/thread-freeres.c
+++ b/malloc/thread-freeres.c
@@ -21,12 +21,13 @@
 #include <resolv/resolv-internal.h>
 #include <rpc/rpc.h>
 #include <string.h>
+#include <libc-symbols.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.  */
-void
+   __libc_subfreeres, skipping calls to it is not a valid optimization.
+   This is called directly from pthread_create as the thread exits.  */
+void __libc_thread_freeres_fn_section
 __libc_thread_freeres (void)
 {
   call_function_static_weak (__rpc_thread_destroy);
diff --git a/nptl/Makefile b/nptl/Makefile
index 0f9c44afa0..2f2bb0569d 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -45,7 +45,7 @@ pthread-compat-wrappers = \
 		      sigwait sigsuspend \
 		      recvmsg sendmsg
 
-libpthread-routines = nptl-init vars events version pt-interp \
+libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
 		      pthread_create pthread_exit pthread_detach \
 		      pthread_join pthread_tryjoin pthread_timedjoin \
 		      pthread_join_common \
diff --git a/nptl/Versions b/nptl/Versions
index 0ae5def464..b1c2da06c0 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -271,5 +271,6 @@ libpthread {
     __pthread_unwind; __pthread_get_minstack;
     __pthread_barrier_init; __pthread_barrier_wait;
     __shm_directory;
+    __libpthread_freeres;
   }
 }
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 9c10b993fd..1af38cbecd 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -32,6 +32,7 @@
 #include <futex-internal.h>
 #include <kernel-features.h>
 #include <stack-aliasing.h>
+#include <libc-symbols.h>
 
 
 #ifndef NEED_SEPARATE_REGISTER_STACK
@@ -251,8 +252,8 @@ get_cached_stack (size_t *sizep, void **memp)
 
 
 /* Free stacks until cache size is lower than LIMIT.  */
-void
-__free_stacks (size_t limit)
+static void
+free_stacks (size_t limit)
 {
   /* We reduce the size of the cache.  Remove the last entries until
      the size is below the limit.  */
@@ -288,6 +289,12 @@ __free_stacks (size_t limit)
     }
 }
 
+/* Free all the stacks on cleanup.  */
+void __libpthread_freeres_fn_section
+__nptl_free_stacks (void)
+{
+  free_stacks (0);
+}
 
 /* Add a stack frame which is not used anymore to the stack.  Must be
    called with the cache lock held.  */
@@ -302,7 +309,7 @@ queue_stack (struct pthread *stack)
 
   stack_cache_actsize += stack->stackblock_size;
   if (__glibc_unlikely (stack_cache_actsize > stack_cache_maxsize))
-    __free_stacks (stack_cache_maxsize);
+    free_stacks (stack_cache_maxsize);
 }
 
 
diff --git a/nptl/libc_pthread_init.c b/nptl/libc_pthread_init.c
index f390480d4b..e254ea2552 100644
--- a/nptl/libc_pthread_init.c
+++ b/nptl/libc_pthread_init.c
@@ -77,11 +77,3 @@ __libc_pthread_init (unsigned long int *ptr, void (*reclaim) (void),
   return &__libc_multiple_threads;
 #endif
 }
-
-#ifdef SHARED
-libc_freeres_fn (freeres_libptread)
-{
-  if (__libc_pthread_functions_init)
-    PTHFCT_CALL (ptr_freeres, ());
-}
-#endif
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index 1d3790f500..907411d5bc 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -78,9 +78,6 @@ extern
 void __nptl_set_robust (struct pthread *);
 
 #ifdef SHARED
-static void nptl_freeres (void);
-
-
 static const struct pthread_functions pthread_functions =
   {
     .ptr_pthread_attr_destroy = __pthread_attr_destroy,
@@ -140,8 +137,6 @@ static const struct pthread_functions pthread_functions =
 # ifdef SIGSETXID
     .ptr__nptl_setxid = __nptl_setxid,
 # endif
-    /* For now only the stack cache needs to be freed.  */
-    .ptr_freeres = nptl_freeres,
     .ptr_set_robust = __nptl_set_robust
   };
 # define ptr_pthread_functions &pthread_functions
@@ -151,16 +146,6 @@ static const struct pthread_functions pthread_functions =
 
 
 #ifdef SHARED
-/* This function is called indirectly from the freeres code in libc.  */
-static void
-__libc_freeres_fn_section
-nptl_freeres (void)
-{
-  __unwind_freeres ();
-  __free_stacks (0);
-}
-
-
 static
 #endif
 void
diff --git a/nptl/nptlfreeres.c b/nptl/nptlfreeres.c
new file mode 100644
index 0000000000..5337d19ace
--- /dev/null
+++ b/nptl/nptlfreeres.c
@@ -0,0 +1,31 @@
+/* Clean up allocated libpthread memory on demand.
+   Copyright (C) 2018 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <set-hooks.h>
+#include <libc-symbols.h>
+#include <pthreadP.h>
+
+/* Free libpthread.so resources.
+   Note: Caller ensures we are called only once.  */
+void  __libpthread_freeres_fn_section
+__libpthread_freeres (void)
+{
+  call_function_static_weak (__nptl_free_stacks);
+  call_function_static_weak (__freeres_shm_directory);
+  call_function_static_weak (__nptl_unwind_freeres);
+}
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 075530c15c..bf9ad27def 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -279,8 +279,8 @@ hidden_proto (__pthread_register_cancel)
 hidden_proto (__pthread_unregister_cancel)
 # ifdef SHARED
 extern void attribute_hidden pthread_cancel_init (void);
-extern void __unwind_freeres (void);
 # endif
+extern void __nptl_unwind_freeres (void) attribute_hidden;
 #endif
 
 
@@ -597,7 +597,8 @@ extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
 extern void __nptl_set_robust (struct pthread *self);
 #endif
 
-extern void __free_stacks (size_t limit) attribute_hidden;
+extern void __nptl_free_stacks (void) attribute_hidden;
+extern void __freeres_shm_directory (void) attribute_hidden;
 
 extern void __wait_lookup_done (void) attribute_hidden;
 
diff --git a/resolv/res-close.c b/resolv/res-close.c
index 38572b1d2f..577eea2b49 100644
--- a/resolv/res-close.c
+++ b/resolv/res-close.c
@@ -87,6 +87,7 @@
 #include <resolv_conf.h>
 #include <not-cancel.h>
 #include <stdlib.h>
+#include <libc-symbols.h>
 
 /* Close all open sockets.  If FREE_ADDR is true, deallocate any
    separately allocated name server addresses.  */
@@ -126,7 +127,7 @@ res_nclose (res_state statp)
 libc_hidden_def (__res_nclose)
 
 /* This is called when a thread is exiting to free resources held in _res.  */
-void
+void __libc_thread_freeres_fn_section
 __res_thread_freeres (void)
 {
   __resolv_context_freeres ();
@@ -140,4 +141,5 @@ __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/resolv_conf.c b/resolv/resolv_conf.c
index b4021ab735..2f0ffbc524 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -23,6 +23,7 @@
 #include <libc-lock.h>
 #include <resolv-internal.h>
 #include <sys/stat.h>
+#include <libc-symbols.h>
 
 /* _res._u._ext.__glibc_extension_index is used as an index into a
    struct resolv_conf_array object.  The intent of this construction
diff --git a/string/strerror_l.c b/string/strerror_l.c
index 2a9c3b5e0b..888524d988 100644
--- a/string/strerror_l.c
+++ b/string/strerror_l.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/param.h>
-
+#include <libc-symbols.h>
 
 static __thread char *last_value;
 
@@ -57,7 +57,7 @@ strerror_l (int errnum, locale_t loc)
 }
 
 
-void
+void __libc_thread_freeres_fn_section
 __strerror_thread_freeres (void)
 {
   free (last_value);
diff --git a/sunrpc/rpc_thread.c b/sunrpc/rpc_thread.c
index a65a90dc15..9872f6b262 100644
--- a/sunrpc/rpc_thread.c
+++ b/sunrpc/rpc_thread.c
@@ -5,6 +5,7 @@
 #include <libc-lock.h>
 #include <libc-tsd.h>
 #include <shlib-compat.h>
+#include <libc-symbols.h>
 
 
 /* Variable used in non-threaded applications or for the first thread.  */
@@ -15,7 +16,7 @@ static __thread struct rpc_thread_variables *thread_rpc_vars
 /*
  * Task-variable destructor
  */
-void
+void __libc_thread_freeres_fn_section
 __rpc_thread_destroy (void)
 {
 	struct rpc_thread_variables *tvp = thread_rpc_vars;
diff --git a/sysdeps/mach/strerror_l.c b/sysdeps/mach/strerror_l.c
index b9842ccf40..628f0d9164 100644
--- a/sysdeps/mach/strerror_l.c
+++ b/sysdeps/mach/strerror_l.c
@@ -24,6 +24,7 @@
 #include <mach/error.h>
 #include <errorlib.h>
 #include <sys/param.h>
+#include <libc-symbols.h>
 
 
 static __thread char *last_value;
@@ -86,8 +87,8 @@ strerror_l (int errnum, locale_t loc)
   return (char *) translate (es->subsystem[sub].codes[code], loc);
 }
 
-
-void
+/* This is called when a thread is exiting to free the last_value string.  */
+void __libc_thread_freeres_fn_section
 __strerror_thread_freeres (void)
 {
   free (last_value);
diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
index 53a4b38fbc..fa103695d9 100644
--- a/sysdeps/nptl/pthread-functions.h
+++ b/sysdeps/nptl/pthread-functions.h
@@ -94,7 +94,6 @@ struct pthread_functions
        __attribute ((noreturn)) __cleanup_fct_attribute;
   void (*ptr__nptl_deallocate_tsd) (void);
   int (*ptr__nptl_setxid) (struct xid_command *);
-  void (*ptr_freeres) (void);
   void (*ptr_set_robust) (struct pthread *);
 };
 
diff --git a/sysdeps/nptl/unwind-forcedunwind.c b/sysdeps/nptl/unwind-forcedunwind.c
index 0621c8002f..9e5dce11ea 100644
--- a/sysdeps/nptl/unwind-forcedunwind.c
+++ b/sysdeps/nptl/unwind-forcedunwind.c
@@ -23,6 +23,7 @@
 #include <sysdep.h>
 #include <gnu/lib-names.h>
 #include <unwind-resume.h>
+#include <libc-symbols.h>
 
 static void *libgcc_s_handle;
 void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
@@ -79,9 +80,9 @@ pthread_cancel_init (void)
   libgcc_s_handle = handle;
 }
 
-void
-__libc_freeres_fn_section
-__unwind_freeres (void)
+/* Register for cleanup in libpthread.so.  */
+void __libpthread_freeres_fn_section
+__nptl_unwind_freeres (void)
 {
   void *handle = libgcc_s_handle;
   if (handle != NULL)
diff --git a/sysdeps/unix/sysv/linux/shm-directory.c b/sysdeps/unix/sysv/linux/shm-directory.c
index c494d3fbf6..58f141cd26 100644
--- a/sysdeps/unix/sysv/linux/shm-directory.c
+++ b/sysdeps/unix/sysv/linux/shm-directory.c
@@ -26,6 +26,7 @@
 #include <sys/statfs.h>
 #include <libc-lock.h>
 #include "linux_fsinfo.h"
+#include <libc-symbols.h>
 
 
 /* Mount point of the shared memory filesystem.  */
@@ -135,13 +136,13 @@ __shm_directory (size_t *len)
 }
 #if IS_IN (libpthread)
 hidden_def (__shm_directory)
-#endif
-
 
 /* Make sure the table is freed if we want to free everything before
    exiting.  */
-libc_freeres_fn (freeit)
+void __libpthread_freeres_fn_section
+__freeres_shm_directory (void)
 {
   if (mountpoint.dir != defaultdir)
     free (mountpoint.dir);
 }
+#endif
