diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index d823fea5645..aa68654ff41 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -39,6 +39,7 @@
 #include "gdbsupport/xml-utils.h"
 #include "trad-frame.h"
 #include "frame-unwind.h"
+#include "inferior.h"
 
 /* If the kernel has to deliver a signal, it pushes a sigcontext
    structure on the stack and then calls the signal handler, passing
@@ -1355,6 +1356,73 @@ rs6000_aix_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch,
 				    offset, len, 0);
 }
 
+/* For AIX, use the rs6000_aix_fetch_tls_load_module_address gdbarch method.
+
+   Thread-local variables accessed via a simple TP-relative offset (the Local
+   Exec and Initial Exec TLS models) are only valid for the main executable and
+   for shared libraries that were pulled in at program startup.  Variables
+   belonging to a library loaded later via dlopen() have their storage
+   allocated dynamically; their addresses must be resolved through the DTV
+   (Dynamic Thread Vector) and cannot be computed with a plain TP offset.
+
+   Until full DTV-based lookup is implemented, reject any objfile that is a
+   shared library (OBJF_SHARED) which has been dlopen'd and only
+   allow the main executable (OBJF_MAINLINE).  Returning 0 here causes
+   rs6000_aix_get_thread_local_address() to be called with lm_addr == 0,
+   which it treats as nothing for now.  */
+
+static CORE_ADDR
+rs6000_aix_fetch_tls_load_module_address (struct objfile *objfile)
+{
+  /* TLS variables from shared libraries cannot be directly fetched
+     via the thread pointer if they were loaded by dlopen().  */
+  if (objfile->flags & OBJF_SHARED)
+    throw_error (TLS_GENERIC_ERROR,
+		 _("TLS lookup via thread pointer is not supported for "
+		   "shared library \"%s\"; full DTV-based lookup is not "
+		   "yet implemented for AIX"),
+		 objfile_name (objfile));
+
+  return 0;
+}
+
+/* Use the AIX get_thread_local_address gdbarch function.
+
+   On 64-bit AIX the thread pointer is in R13.  For the Local Exec TLS model
+   (used by the main executable) the XCOFF symbol value is a signed
+   TP-relative offset, so the per-thread address is:
+
+     address = thread_pointer + (int64_t) offset
+
+   This only works correctly when the variable's storage is allocated
+   statically relative to the thread pointer, which is guaranteed for the
+   main executable. */
+
+static CORE_ADDR
+rs6000_aix_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
+				     CORE_ADDR lm_addr, CORE_ADDR offset)
+{
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  /* 64-bit AIX: the thread pointer is in R13.  */
+  if (tdep->wordsize != 8)
+    throw_error (TLS_GENERIC_ERROR,
+		 _("TLS lookup not yet supported for 32-bit AIX"));
+
+  int tp_regnum = PPC_R0_REGNUM + 13;
+
+  regcache *regcache
+    = get_thread_arch_regcache (current_inferior (), ptid, gdbarch);
+  target_fetch_registers (regcache, tp_regnum);
+
+  ULONGEST tp;
+  if (regcache->cooked_read (tp_regnum, &tp) != REG_VALID)
+    throw_error (TLS_GENERIC_ERROR,
+		 _("Unable to fetch thread pointer for TLS lookup"));
+
+  return tp + (CORE_ADDR)(int64_t) offset;
+}
+
 static void
 rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1411,6 +1479,14 @@ rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_auto_wide_charset (gdbarch, rs6000_aix_auto_wide_charset);
 
   set_gdbarch_make_solib_ops (gdbarch, make_aix_solib_ops);
+
+
+  /* TLS support for AIX.  */
+  set_gdbarch_fetch_tls_load_module_address
+    (gdbarch, rs6000_aix_fetch_tls_load_module_address);
+  set_gdbarch_get_thread_local_address
+    (gdbarch, rs6000_aix_get_thread_local_address);
+
   frame_unwind_append_unwinder (gdbarch, &aix_sighandle_frame_unwind);
 }
 
