diff --git a/elf/Makefile b/elf/Makefile
index 94074f3..34f0b1f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -904,7 +904,7 @@ CFLAGS-tst-pie2.c += $(pie-ccflag)
 $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
 
 ifeq (yes,$(build-shared))
-all-built-dso := $(common-objpfx)libc.so \
+all-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \
 		 $(filter-out $(common-objpfx)linkobj/libc.so, \
 			      $(sort $(wildcard $(addprefix $(common-objpfx), \
 							    */lib*.so \
@@ -963,6 +963,7 @@ common-generated += $(all-built-dso:$(common-objpfx)%=%.jmprel)
 
 localplt-built-dso := $(addprefix $(common-objpfx),\
 				  libc.so \
+				  elf/ld.so \
 				  math/libm.so \
 				  rt/librt.so \
 				  dlfcn/libdl.so \
diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
index d296519..d7d6734 100644
--- a/sysdeps/generic/localplt.data
+++ b/sysdeps/generic/localplt.data
@@ -7,3 +7,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
index dfca9a7..a3392d3 100644
--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
+++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
@@ -12,3 +12,12 @@ libm.so: matherr
 libm.so: __signbit
 libm.so: __signbitf
 libm.so: __signbitl
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
index 6b2e515..e2a4311 100644
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -24,3 +24,12 @@ libm.so: matherr
 # We used to offer inline functions that used this, so it must be exported.
 # Ought to reorg things such that carg isn't thus forced to use a plt.
 libm.so: __atan2
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
index 109522e..85160bd 100644
--- a/sysdeps/unix/sysv/linux/arm/localplt.data
+++ b/sysdeps/unix/sysv/linux/arm/localplt.data
@@ -11,3 +11,12 @@ libm.so: __signbitf
 libm.so: matherr
 libpthread.so: __errno_location
 libpthread.so: raise
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
index 8fb56b6..009797b 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -5,3 +5,14 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs ___tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+# Note that it is triple underscore for ___tls_get_addr e.g. the alternate
+# ABI.
+ld.so: ___tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
index ba48816..bc2ce41 100644
--- a/sysdeps/unix/sysv/linux/ia64/localplt.data
+++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
@@ -6,3 +6,12 @@ libc.so: realloc
 libm.so: matherr
 libm.so: matherrf
 libm.so: matherrl
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/m68k/localplt.data b/sysdeps/unix/sysv/linux/m68k/localplt.data
index d266b8f..15a9fe5 100644
--- a/sysdeps/unix/sysv/linux/m68k/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/localplt.data
@@ -6,3 +6,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
index 6dd5bcb..f488c95 100644
--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
+++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
@@ -9,3 +9,12 @@ libm.so: __signbit
 libm.so: __signbitf
 libm.so: matherr
 libpthread.so: __errno_location
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
index 8fb56b6..619b417 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
@@ -5,3 +5,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
index 6332a00..78ecd4a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
@@ -38,3 +38,12 @@ libm.so: __signbitl
 libm.so: copysignl ?
 libm.so: fabsl
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
index 2219aa9..75bcee6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
@@ -4,3 +4,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader uses __libc_memalign internally to allocate aligned
+# TLS storage. The other malloc family of functions are expected to
+# allow user symbol interposition. Note that because of the way the TLS
+# ABI works there is no PLT call to __tls_get_addr on ppc64 and ppc64le.
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
index 8fb56b6..619b417 100644
--- a/sysdeps/unix/sysv/linux/s390/localplt.data
+++ b/sysdeps/unix/sysv/linux/s390/localplt.data
@@ -5,3 +5,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
index 15ba18b..81c1650 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
@@ -15,3 +15,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
index 6f1769c..d6f9e02 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
@@ -17,3 +17,12 @@ libc.so: malloc
 libc.so: memalign
 libc.so: realloc
 libm.so: matherr
+# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign
+# internally to allocate aligned TLS storage. The other malloc family of
+# functions are expected to allow user symbol interposition.
+ld.so: __tls_get_addr
+ld.so: __libc_memalign
+ld.so: malloc
+ld.so: calloc
+ld.so: realloc
+ld.so: free
