diff --git a/elf/Makefile b/elf/Makefile
index dbc6cfec7fe..d9abbad1cf7 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -529,6 +529,7 @@ tests += \
   tst-tlsalign \
   tst-tlsalign-extern \
   tst-tlsgap \
+  tst-trace-tls \
   tst-unique1 \
   tst-unique2 \
   tst-unwind-ctor \
@@ -1108,6 +1109,7 @@ modules-names += \
   tst-tlsmod7 \
   tst-tlsmod8 \
   tst-tlsmod9 \
+  tst-trace-tls-mod \
   tst-unique1mod1 \
   tst-unique1mod2 \
   tst-unique2mod1 \
@@ -3544,6 +3546,9 @@ $(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \
 $(objpfx)tst-nodeps2.out: \
   $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so
 
+$(objpfx)tst-trace-tls.out: $(objpfx)tst-trace-tls-mod.so $(objpfx)ld.so
+tst-trace-tls-mod.so-no-z-defs = yes
+
 $(objpfx)tst-tlsgap: $(shared-thread-library)
 $(objpfx)tst-tlsgap.out: \
   $(objpfx)tst-tlsgap-mod0.so \
diff --git a/elf/tst-trace-tls-mod.c b/elf/tst-trace-tls-mod.c
new file mode 100644
index 00000000000..7b855fd814c
--- /dev/null
+++ b/elf/tst-trace-tls-mod.c
@@ -0,0 +1,41 @@
+/* Shared object with relocations against undefined TLS symbols.
+   Copyright (C) 2026 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 __thread int missing_tls_gd
+  __attribute__ ((tls_model ("global-dynamic")));
+extern __thread int missing_tls_ie
+  __attribute__ ((tls_model ("initial-exec")));
+extern int missing_data;
+
+int
+access_tls_gd (void)
+{
+  return missing_tls_gd;
+}
+
+int
+access_tls_ie (void)
+{
+  return missing_tls_ie;
+}
+
+int
+access_data (void)
+{
+  return missing_data;
+}
diff --git a/elf/tst-trace-tls.c b/elf/tst-trace-tls.c
new file mode 100644
index 00000000000..2d541b1a519
--- /dev/null
+++ b/elf/tst-trace-tls.c
@@ -0,0 +1,82 @@
+/* Check that trace mode handles unresolved TLS symbols (bug XXXXX).
+   Copyright (C) 2026 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/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* Check if unresolved TLS symbol in trace mode (LD_TRACE_LOADED_OBJECTS)
+   is correctly reported.  */
+
+static char *mod;
+
+static struct support_capture_subprocess
+run_ldso (const char *env1, const char *env2)
+{
+  char *const argv[] =
+    { (char *) support_objdir_elf_ldso, (char *) mod, NULL };
+  char *const envp[] =
+    { (char *) "LD_TRACE_LOADED_OBJECTS=1", (char *) env1, (char *) env2,
+      NULL };
+
+  struct support_capture_subprocess result
+    = support_capture_subprogram (argv[0], argv, envp);
+  support_capture_subprocess_check (&result, "tst-trace-tls", 0,
+				    sc_allow_stdout | sc_allow_stderr);
+  return result;
+}
+
+static void
+run_trace (const char *title, const char *env1, const char *env2,
+	   bool check_undefined)
+{
+  printf ("info: checking %s\n", title);
+
+  struct support_capture_subprocess result = run_ldso (env1, env2);
+
+  if (check_undefined)
+    {
+      TEST_VERIFY (strstr (result.err.buffer,
+			   "undefined symbol: missing_tls_gd") != NULL);
+      TEST_VERIFY (strstr (result.err.buffer,
+			   "undefined symbol: missing_tls_ie") != NULL);
+      TEST_VERIFY (strstr (result.err.buffer,
+			   "undefined symbol: missing_data") != NULL);
+    }
+
+  support_capture_subprocess_free (&result);
+}
+
+static int
+do_test (void)
+{
+  mod = xasprintf ("%s/elf/tst-trace-tls-mod.so", support_objdir_root);
+
+  run_trace ("ldd -d", "LD_WARN=yes", NULL, true);
+  run_trace ("ldd -r", "LD_WARN=yes", "LD_BIND_NOW=1", true);
+  run_trace ("ldd -u", "LD_DEBUG=unused", NULL, false);
+
+  free (mod);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index 9bdbd85b6b3..ba2e4123c6e 100644
--- a/sysdeps/hppa/dl-machine.h
+++ b/sysdeps/hppa/dl-machine.h
@@ -700,7 +700,9 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
 
 #if !defined RTLD_BOOTSTRAP
     case R_PARISC_TLS_DTPMOD32:
-      value = sym_map->l_tls_modid;
+      /* The sym_map may be NULL in trace mode (LD_TRACE_LOADED_OBJECTS).  */
+      if (sym_map != NULL)
+	value = sym_map->l_tls_modid;
       break;
 
     case R_PARISC_TLS_DTPOFF32:
diff --git a/sysdeps/loongarch/dl-machine.h b/sysdeps/loongarch/dl-machine.h
index ae295264ae9..1fb2635f92e 100644
--- a/sysdeps/loongarch/dl-machine.h
+++ b/sysdeps/loongarch/dl-machine.h
@@ -197,16 +197,22 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
 
 #ifndef RTLD_BOOTSTRAP
     case __WORDSIZE == 64 ? R_LARCH_TLS_DTPMOD64 : R_LARCH_TLS_DTPMOD32:
-      *addr_field = sym_map->l_tls_modid;
+      /* The sym_map may be NULL in trace mode (LD_TRACE_LOADED_OBJECTS).  */
+      if (sym_map != NULL)
+	*addr_field = sym_map->l_tls_modid;
       break;
 
     case __WORDSIZE == 64 ? R_LARCH_TLS_DTPREL64 : R_LARCH_TLS_DTPREL32:
-      *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
+      if (sym != NULL)
+	*addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
       break;
 
     case __WORDSIZE == 64 ? R_LARCH_TLS_TPREL64 : R_LARCH_TLS_TPREL32:
-      CHECK_STATIC_TLS (map, sym_map, sym);
-      *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
+      if (sym != NULL)
+	{
+	  CHECK_STATIC_TLS (map, sym_map, sym);
+	  *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
+	}
       break;
 
     case __WORDSIZE == 64 ? R_LARCH_TLS_DESC64 : R_LARCH_TLS_DESC32:
