diff --git a/gdb/testsuite/gdb.base/tls-multiobj.c b/gdb/testsuite/gdb.base/tls-multiobj.c
new file mode 100644
index 00000000000..10e67da54d8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+__thread int tls_main_tbss_1;
+__thread int tls_main_tbss_2;
+__thread int tls_main_tdata_1 = 96;
+__thread int tls_main_tdata_2 = 97;
+
+extern __thread int tls_lib1_tbss_1;
+extern __thread int tls_lib1_tbss_2;
+extern __thread int tls_lib1_tdata_1;
+extern __thread int tls_lib1_tdata_2;
+
+extern __thread int tls_lib2_tbss_1;
+extern __thread int tls_lib2_tbss_2;
+extern __thread int tls_lib2_tdata_1;
+extern __thread int tls_lib2_tdata_2;
+
+extern __thread int tls_lib3_tbss_1;
+extern __thread int tls_lib3_tbss_2;
+extern __thread int tls_lib3_tdata_1;
+extern __thread int tls_lib3_tdata_2;
+
+extern void lib1_func ();
+extern void lib2_func ();
+extern void lib3_func ();
+
+volatile int data;
+
+void
+use_it (int a)
+{
+  data = a;
+}
+
+int
+main (int argc, char **argv)
+{
+  use_it (-1);
+
+  tls_main_tbss_1 = 51;	/* main-breakpoint-1 */
+  tls_main_tbss_2 = 52;
+  tls_main_tdata_1 = 53;
+  tls_main_tdata_2 = 54;
+
+  tls_lib1_tbss_1 = 151;
+  tls_lib1_tbss_2 = 152;
+  tls_lib1_tdata_1 = 153;
+  tls_lib1_tdata_2 = 154;
+
+  tls_lib2_tbss_1 = 251;
+  tls_lib2_tbss_2 = 252;
+  tls_lib2_tdata_1 = 253;
+  tls_lib2_tdata_2 = 254;
+
+  tls_lib3_tbss_1 = 351;
+  tls_lib3_tbss_2 = 352;
+  tls_lib3_tdata_1 = 353;
+  tls_lib3_tdata_2 = 354;
+
+  lib1_func ();
+  lib2_func ();
+  lib3_func ();
+
+  /* Attempt to keep variables in the main program from being optimized
+     away.  */
+  use_it (tls_main_tbss_1);
+  use_it (tls_main_tbss_2);
+  use_it (tls_main_tdata_1);
+  use_it (tls_main_tdata_2);
+
+  use_it (100);		/* main-breakpoint-2 */
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj.exp b/gdb/testsuite/gdb.base/tls-multiobj.exp
new file mode 100644
index 00000000000..a78db1460e9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj.exp
@@ -0,0 +1,230 @@
+# Copyright 2024 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+
+# Using different compilation/linking scenarios, attempt to access
+# thread-local variables in a non-threaded program using multiple
+# shared objects.
+
+source $srcdir/$subdir/tls-common.exp.tcl
+
+standard_testfile
+
+set lib1src "${srcdir}/${subdir}/${testfile}1.c"
+set lib2src "${srcdir}/${subdir}/${testfile}2.c"
+set lib3src "${srcdir}/${subdir}/${testfile}3.c"
+
+set lib1obj [standard_output_file "${testfile}1-lib.so"]
+set lib2obj [standard_output_file "${testfile}2-lib.so"]
+set lib3obj [standard_output_file "${testfile}3-lib.so"]
+
+proc do_tests {force_internal_tls {do_kfail_tls_access 0}} {
+    clean_restart $::binfile
+    if ![runto_main] {
+	return
+    }
+
+    if $force_internal_tls {
+	gdb_test_no_output "maint set force-internal-tls-address-lookup on"
+    }
+
+    if { $do_kfail_tls_access && [istarget "*-*-linux*"] } {
+	# Turn off do_kfail_tls_access when libthread_db is loaded. 
+	# This can happen for the default case when testing x86_64
+	# w/ -m32 using glibc versions 2.34 or newer.
+	gdb_test_multiple "maint check libthread-db" "Check for loaded libthread_db" {
+	    -re -wrap "libthread_db integrity checks passed." {
+		set do_kfail_tls_access 0
+		pass $gdb_test_name
+	    }
+	    -re -wrap "No libthread_db loaded" {
+		pass $gdb_test_name
+	    }
+	}
+	# Also turn off do_kfail_tls_access when connected to a
+	# gdbserver and we observe that accessing a TLS variable
+	# works.
+	if [target_is_gdbserver] {
+	    gdb_test_multiple "print tls_main_tbss_1" \
+		"Check TLS accessibility when connected to a gdbserver" {
+		-re -wrap "= 0" {
+		    set do_kfail_tls_access 0
+		    pass $gdb_test_name
+		}
+		-re -wrap "Remote target failed to process qGetTLSAddr request" {
+		    pass $gdb_test_name
+		}
+	    }
+	}
+    }
+
+    gdb_breakpoint [gdb_get_line_number "main-breakpoint-1"]
+    gdb_continue_to_breakpoint "main-breakpoint-1"
+
+    set t $do_kfail_tls_access
+    set m "tls not available"
+    with_test_prefix "before assignments" {
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 96" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 97" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 196" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 197" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 296" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 297" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 396" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 397" $t $m
+    }
+
+    gdb_breakpoint [gdb_get_line_number "main-breakpoint-2"]
+    gdb_continue_to_breakpoint "main-breakpoint-2"
+
+    with_test_prefix "after assignments" {
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 51" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 52" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 53" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 54" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 151" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 152" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 153" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 154" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 251" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 252" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 253" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 254" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 351" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 352" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 353" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 354" $t $m
+    }
+
+    set corefile ${::binfile}.core
+    set core_supported 0
+    if { ![is_remote host] } {
+	set core_supported [gdb_gcore_cmd $corefile "save corefile"]
+    }
+
+    # Finish test early if no core file was made.
+    if !$core_supported {
+	return
+    }
+
+    clean_restart $::binfile
+
+    set core_loaded [gdb_core_cmd $corefile "load corefile"]
+    if { $core_loaded == -1 } {
+	return
+    }
+
+    with_test_prefix "core file" {
+	if $force_internal_tls {
+	    gdb_test_no_output "maint set force-internal-tls-address-lookup on"
+	}
+
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 51" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 52" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 53" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 54" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 151" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 152" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 153" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 154" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 251" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 252" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 253" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 254" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 351" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 352" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 353" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 354" $t $m
+    }
+}
+
+if { [gdb_compile_shlib $lib1src $lib1obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+if { [gdb_compile_shlib $lib2src $lib2obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+if { [gdb_compile_shlib $lib3src $lib3obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+
+# Certain linux target architectures implement support for internal
+# TLS lookup which is used when thread stratum support (via
+# libthread_db) is missing or when the linux-only GDB maintenance
+# setting 'force-internal-tls-address-lookup' is 'on'.  Thus for some
+# of the testing scenarios, such as statically linked executables,
+# this internal support will be used.  Set 'do_kfail_tls_access' to 1
+# for those architectures which don't implement internal tls support.
+if {[istarget *-*-linux*]
+    && ![is_any_target {*}$internal_tls_linux_targets]} {
+    set do_kfail_tls_access 1
+} elseif {[istarget *-*-linux*] && [is_x86_like_target]} {
+    # This covers the case of x86_64 with -m32:
+    set do_kfail_tls_access 1
+} else {
+    set do_kfail_tls_access 0
+}
+
+set binprefix $binfile
+
+with_test_prefix "default" {
+    set binfile $binprefix-default
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+                        [list debug shlib=${lib1obj} \
+			            shlib=${lib2obj} \
+				    shlib=${lib3obj}]] != "" } {
+	untested "failed to compile"
+    } else {
+	foreach_with_prefix force_internal_tls $internal_tls_iters {
+	    # Depending on glibc version, it might not be appropriate
+	    # for do_kfail_tls_access to be set here.  That will be
+	    # handled in 'do_tests', disabling it if necessary.
+	    # 
+	    # Specifically, glibc versions 2.34 and later have the
+	    # thread library (and libthread_db availability) in
+	    # programs not linked against libpthread.so
+	    do_tests $force_internal_tls $do_kfail_tls_access
+	}
+    }
+}
+
+with_test_prefix "pthreads" {
+    set binfile $binprefix-pthreads
+    if	{ [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+				 [list debug shlib=${lib1obj} \
+					     shlib=${lib2obj} \
+					     shlib=${lib3obj}]] != "" } {
+	untested "failed to compile"
+    } else {
+	foreach_with_prefix force_internal_tls $internal_tls_iters {
+	    do_tests $force_internal_tls
+	}
+    }
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj1.c b/gdb/testsuite/gdb.base/tls-multiobj1.c
new file mode 100644
index 00000000000..86e72228b1b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj1.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+__thread int tls_lib1_tbss_1;
+__thread int tls_lib1_tbss_2;
+__thread int tls_lib1_tdata_1 = 196;
+__thread int tls_lib1_tdata_2 = 197;
+
+void
+lib1_func ()
+{
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj2.c b/gdb/testsuite/gdb.base/tls-multiobj2.c
new file mode 100644
index 00000000000..cea07092a5d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj2.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+__thread int tls_lib2_tbss_1;
+__thread int tls_lib2_tbss_2;
+__thread int tls_lib2_tdata_1 = 296;
+__thread int tls_lib2_tdata_2 = 297;
+
+void
+lib2_func ()
+{
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj3.c b/gdb/testsuite/gdb.base/tls-multiobj3.c
new file mode 100644
index 00000000000..bb0f2395fbf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj3.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+__thread int tls_lib3_tbss_1;
+__thread int tls_lib3_tbss_2;
+__thread int tls_lib3_tdata_1 = 396;
+__thread int tls_lib3_tdata_2 = 397;
+
+void
+lib3_func ()
+{
+}
