From: Aditya Vidyadhar Kamath <akamath996@gmail.com>
To: ulrich.weigand@de.ibm.com, simon.marchi@polymtl.ca, tom@tromey.com
Cc: gdb-patches@sourceware.org, Aditya.Kamath1@ibm.com,
sangamesh.swamy@in.ibm.com,
Aditya Vidyadhar Kamath <aditya.kamath1@ibm.com>
Subject: [PATCH v2 2/2] This patch adds support to debug thread local variables defined in shared libraries in AIX.
Date: Thu, 3 Sep 2026 14:26:15 +0530 [thread overview]
Message-ID: <20260903085614.39532-2-akamath996@gmail.com> (raw)
From: Aditya Vidyadhar Kamath <aditya.kamath1@ibm.com>
Sample debug output of this patch is as below
Thread 3 hit Breakpoint 1, thread_runner (arg=0x2) at tls_main.c:36
36 volatile int bp_here = 0; (void)bp_here;
$3 = 20
$4 = 40
thread 2: my_tls_var=20 lib_tls_var=40
[Thread 1 (tid 101646715) (id 1) exited]
[Thread 515 (tid 88015327) (id 3) exited]
[Inferior 1 (process 21758254) exited normally]
where lib_tls_var=40 is a variable from a thread library.
There are 4 models for TLS varialbles in AIX,
Local exec means the TLS variable is in main executable and defined there only.
Initial exec means the TLS variable is in a library and is linked in start up.
Global dynamic means TLS variable is in shared module and loaded when we dlopen
Local dynamic means TLS varialbe is in shared module it is local to the shared library code.
So local dynamic variables the compiler can group together for a shared look up.
This local-dymanic case is handled in rs6000_aix_compute_tls_address ()
For initial-exec (R_TLS_IE): read the runtime TP-relative offset from the
.loader section TOC slot written by the AIX loader, returning it with bit 0
set as a sentinel so get_thread_local_address() uses it directly without
re-adding the static symbol value.
For global-dynamic/local-dynamic (R_TLSM): scan the .loader section for the
R_TLSM relocation, read the 8-byte mod_id from the inferior's TOC, and
dereference it as a TP-relative pointer to the per-thread block, then add the
intra-module variable offset.
Local-exec (main executable) continues to use the existing tp + offset path.
This patch implements the same as mentioned above.
---
gdb/rs6000-aix-tdep.c | 509 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 498 insertions(+), 11 deletions(-)
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 76763f08e08..c4bc01c381e 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -40,6 +40,10 @@
#include "trad-frame.h"
#include "frame-unwind.h"
#include "inferior.h"
+#include "coff/internal.h"
+#include "libcoff.h"
+#include "coff/xcoff.h"
+#include "libxcoff.h"
/* If the kernel has to deliver a signal, it pushes a sigcontext
structure on the stack and then calls the signal handler, passing
@@ -69,6 +73,40 @@
/* Minimum possible text address in AIX. */
#define AIX_TEXT_SEGMENT_BASE 0x10000000
+/* XCOFF TLS relocation types (low byte of internal_ldrel.l_rtype).
+
+ The AIX loader fills TLS TOC slots as follows:
+
+ R_TLS (0x20, global-dynamic): the loader writes the signed TP-relative
+ offset for the variable. For multi-module programs this value is only
+ meaningful relative to the module's own TLS block base; to get the true
+ address the thread_vector must be consulted via __tls_get_addr.
+
+ R_TLS_IE (0x21, initial-exec): the loader writes the signed TP-relative
+ offset directly. address = tp + toc_val is always correct here.
+
+ R_TLS_LD (0x22, local-dynamic): the loader writes the module-relative
+ offset of the variable within the module's TLS block.
+
+ R_TLS_LE (0x23, local-exec): resolved statically by the linker; no
+ TOC slot is emitted at runtime.
+
+ R_TLSM (0x24): the loader writes the module-id for the module
+ that owns the variable. Used with R_TLS.
+
+ R_TLSML (0x25): the loader writes the module-id for the current module.
+ Used with R_TLS_LD one slot per module, shared by all
+ local-dynamic variables in that module.
+
+*/
+
+#define XCOFF_R_TLS 0x20
+#define XCOFF_R_TLS_IE 0x21
+#define XCOFF_R_TLS_LD 0x22
+#define XCOFF_R_TLS_LE 0x23
+#define XCOFF_R_TLSM 0x24
+#define XCOFF_R_TLSML 0x25
+
struct rs6000_aix_reg_vrreg_offset
{
int vr0_offset;
@@ -84,6 +122,27 @@ static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
560 /* vrsave_offset */
};
+/* Description of a single TLS relocation found by scanning the .loader
+ section. Used as the return value of rs6000_aix_find_tls_reloc. */
+
+struct aix_tls_reloc_info
+{
+ /* The TLS model - XCOFF_R_TLS or XCOFF_R_TLS_IE or XCOFF_R_TLS_LD,
+ or XCOFF_R_TLS_LE. */
+ int rtype = -1;
+
+ /* Runtime address of the primary TOC slot. */
+ CORE_ADDR toc_addr = 0;
+
+ /* For global-dynamic: runtime address of the paired R_TLSM slot
+ that holds the module-id. 0 if not found. */
+ CORE_ADDR modid_toc_addr = 0;
+
+ /* For local-dynamic: runtime address of the R_TLSML slot that
+ holds the module-id for the whole module. 0 if not found. */
+ CORE_ADDR modid_ld_addr = 0;
+};
+
static int
rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
const struct rs6000_aix_reg_vrreg_offset *offsets,
@@ -1361,21 +1420,369 @@ rs6000_aix_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch,
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)
+ /* Main executable so lm_addr == 0. */
+ if (!(objfile->flags & OBJF_SHARED))
+ return 0;
+
+ /* Return the objfile pointer as the lm_addr token. The per-variable
+ TOC-slot lookup is done in rs6000_aix_get_thread_local_address where
+ the static symbol value is also available. */
+ if (objfile->obfd.get () == nullptr)
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));
+ _("Cannot resolve TLS for \"%s\": no BFD"),
+ objfile_name (objfile));
- return 0;
+ return (CORE_ADDR)(uintptr_t) objfile;
+}
+
+/* Helper to read an 8-byte slot from the inferior at RUNTIME_ADDR.
+ Returns the value as a signed 64-bit integer, or throws TLS_GENERIC_ERROR
+ on a memory read failure. */
+
+static int64_t
+rs6000_aix_read_tls_slot (CORE_ADDR runtime_addr, const char *objfile_name_str)
+{
+ gdb_byte buf[8];
+ if (target_read_memory (runtime_addr, buf, sizeof buf) != 0)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": "
+ "failed to read TLS TOC slot at %s from inferior"),
+ objfile_name_str,
+ core_addr_to_string (runtime_addr));
+ return (int64_t) extract_unsigned_integer (buf, sizeof buf, BFD_ENDIAN_BIG);
+}
+
+/* Read the AIX thread entry for module MOD_ID and return the base address of
+ that module's TLS block. On 64-bit AIX the pointer is stored at the
+ address pointed to by the thread pointer (tp):
+ thread_ptr = *(uint64_t *) tp
+ tls_base = thread_ptr[mod_id]
+ Each entry is a single 8-byte pointer. Returns 0 if the slot has not
+ been allocated yet (throws TLS_NOT_ALLOCATED_YET_ERROR in that case). */
+
+static CORE_ADDR
+rs6000_aix_thread_vec_lookup (ULONGEST tp, uint64_t mod_id,
+ const char *objfile_name_str)
+{
+ /* The thread vector pointer lives at *tp on AIX 64-bit. */
+ gdb_byte buf[8];
+ if (target_read_memory ((CORE_ADDR) tp, buf, sizeof buf) != 0)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": "
+ "failed to read thread vector pointer at tp=%s"),
+ objfile_name_str,
+ core_addr_to_string ((CORE_ADDR) tp));
+
+ CORE_ADDR thread_ptr
+ = (CORE_ADDR) extract_unsigned_integer (buf, sizeof buf, BFD_ENDIAN_BIG);
+
+ if (thread_ptr == 0)
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS storage not yet allocated for \"%s\""),
+ objfile_name_str);
+
+ /* thread_ptr[mod_id] is the TLS block base for this module. */
+ CORE_ADDR thread_entry_addr = thread_ptr + mod_id * sizeof (uint64_t);
+ if (target_read_memory (thread_entry_addr, buf, sizeof buf) != 0)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": "
+ "failed to read thread_vec[%s] at %s"),
+ objfile_name_str,
+ pulongest (mod_id),
+ core_addr_to_string (thread_entry_addr));
+
+ CORE_ADDR tls_base
+ = (CORE_ADDR) extract_unsigned_integer (buf, sizeof buf, BFD_ENDIAN_BIG);
+
+ if (tls_base == 0)
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS storage not yet allocated for \"%s\" (thread vector[%s] == 0)"),
+ objfile_name_str, pulongest (mod_id));
+
+ return tls_base;
}
-/* Implement the get_thread_local_address gdbarch method for AIX.
+/* Scan the .loader section of ABFD for a TLS relocation whose loader symbol
+ value matches SYM_OFFSET. Returns an aix_tls_reloc_info describing what was
+ found, or one with rtype == -1 if no matching relocation exists.
+
+ For global-dynamic (R_TLS), also walks the reloc table looking for the
+ paired R_TLSM entry that has the same l_vaddr as the R_TLS slot minus
+ one pointer-width, which is how the AIX ABI lays out the two-word
+ {modid, offset} structure in the TOC.
+
+ For local-dynamic (R_TLS_LD), locates the corresponding R_TLSML reloc
+ which is always self-referencing -- l_symndx == the TOC entry's own csect
+ index in the same object. */
+
+static aix_tls_reloc_info
+rs6000_aix_find_tls_reloc (bfd *abfd,
+ CORE_ADDR data_slide,
+ const gdb::byte_vector &loader_buf,
+ CORE_ADDR sym_offset)
+{
+ aix_tls_reloc_info result;
+
+ struct internal_ldhdr ldhdr;
+ bfd_xcoff_swap_ldhdr_in (abfd, loader_buf.data (), &ldhdr);
+
+ bfd_size_type loader_size = loader_buf.size ();
+ bfd_vma sym_start = bfd_xcoff_loader_symbol_offset (abfd, &ldhdr);
+ bfd_size_type symsz = bfd_xcoff_ldsymsz (abfd);
+ bfd_vma reloc_start = bfd_xcoff_loader_reloc_offset (abfd, &ldhdr);
+ bfd_size_type relsz = bfd_xcoff_ldrelsz (abfd);
+
+ if (reloc_start + ldhdr.l_nreloc * relsz > loader_size)
+ return result;
+
+ /* Find the primary TLS reloc for this variable. */
+ const gdb_byte *reloc_ptr = loader_buf.data () + reloc_start;
+ for (size_t i = 0; i < ldhdr.l_nreloc; i++, reloc_ptr += relsz)
+ {
+ struct internal_ldrel ldrel;
+ bfd_xcoff_swap_ldrel_in (abfd, reloc_ptr, &ldrel);
+
+ int rtype = ldrel.l_rtype & 0xff;
+ if (rtype != XCOFF_R_TLS && rtype != XCOFF_R_TLS_IE
+ && rtype != XCOFF_R_TLS_LD)
+ continue;
+
+ /* l_symndx values 0..2 are section references; loader symbol indices
+ start at 3. */
+ if (ldrel.l_symndx < 3
+ || (bfd_vma)(ldrel.l_symndx - 3) >= ldhdr.l_nsyms)
+ continue;
+
+ bfd_vma ldsym_off = sym_start + (bfd_vma)(ldrel.l_symndx - 3) * symsz;
+ if (ldsym_off + symsz > loader_size)
+ continue;
+
+ struct internal_ldsym ldsym;
+ bfd_xcoff_swap_ldsym_in (abfd, loader_buf.data () + ldsym_off, &ldsym);
+
+
+ /* Match: the loader symbol's l_value equals the XCOFF static symbol
+ value that GDB received as 'sym_offset'. For R_TLS and R_TLS_IE
+ this is the TP-relative offset baked in at link time. For R_TLS_LD
+ this is the within-module variable offset. */
+ if ((CORE_ADDR)(int64_t) ldsym.l_value != sym_offset)
+ continue;
+
+ result.rtype = rtype;
+ result.toc_addr = ldrel.l_vaddr + data_slide;
+ break;
+ }
+
+ if (result.rtype == -1)
+ return result; /* No matching reloc found. */
+
+ /* Find the paired R_TLSM slot.
+ The AIX ABI places the two-word {modid, offset} GD descriptor in the
+ TOC at consecutive 8-byte slots. The R_TLSM reloc targets the first
+ word = modid and the R_TLS reloc targets the second word = offset.
+ So the R_TLSM slot lives at result.toc_addr - 8. We verify this by
+ scanning for an R_TLSM reloc with l_vaddr == result.toc_addr - 8. */
+ if (result.rtype == XCOFF_R_TLS)
+ {
+ bfd_vma expected_tlsm_vaddr = (result.toc_addr - data_slide) - 8;
+ reloc_ptr = loader_buf.data () + reloc_start;
+ for (size_t i = 0; i < ldhdr.l_nreloc; i++, reloc_ptr += relsz)
+ {
+ struct internal_ldrel ldrel;
+ bfd_xcoff_swap_ldrel_in (abfd, reloc_ptr, &ldrel);
+
+ if ((ldrel.l_rtype & 0xff) != XCOFF_R_TLSM)
+ continue;
+ if (ldrel.l_vaddr == expected_tlsm_vaddr)
+ {
+ result.modid_toc_addr = ldrel.l_vaddr + data_slide;
+ break;
+ }
+ }
+ }
+
+ /* For local-dynamic is to find the R_TLSML reloc in the same
+ object. There is exactly one R_TLSML per module; it is self-targeting
+ i.e. the loader symbol it references is the TOC entry itself. */
+ if (result.rtype == XCOFF_R_TLS_LD)
+ {
+ reloc_ptr = loader_buf.data () + reloc_start;
+ for (size_t i = 0; i < ldhdr.l_nreloc; i++, reloc_ptr += relsz)
+ {
+ struct internal_ldrel ldrel;
+ bfd_xcoff_swap_ldrel_in (abfd, reloc_ptr, &ldrel);
+
+ if ((ldrel.l_rtype & 0xff) != XCOFF_R_TLSML)
+ continue;
+
+ result.modid_ld_addr = ldrel.l_vaddr + data_slide;
+ break;
+ }
+ }
+
+ return result;
+}
- On 64-bit AIX the thread pointer (TP) is in R13. For variables in
+/* Cross-objfile fallback for the variable's owning objfile has no matching TLS
+ loader reloc (Ex: the variable is only accessed via __tls_get_addr from
+ code, not via a loader-section TOC slot). Search every other loaded objfile
+ for an R_TLS_IE or R_TLS reloc whose loader symbol l_value matches OFFSET.
+
+ On AIX with GCC, the main executable typically has R_TLS_IE relocs for
+ cross-module TLS variables, even when the defining .so has no matching
+ R_TLS / R_TLSM loader relocs for them. The R_TLS_IE TOC slot value is
+ the signed TP-relative offset, valid as: address = tp + toc_val.
+
+ Returns a filled aix_tls_reloc_info, or one with rtype==-1 if not found. */
+
+static aix_tls_reloc_info
+rs6000_aix_scan_all_objfiles (CORE_ADDR offset)
+{
+ for (objfile &candidate : current_program_space->objfiles ())
+ {
+ if (candidate.obfd.get () == nullptr)
+ continue;
+
+ bfd *abfd = candidate.obfd.get ();
+ asection *loader_sec = bfd_get_section_by_name (abfd, ".loader");
+ if (loader_sec == nullptr)
+ continue;
+
+ bfd_size_type loader_size = bfd_section_size (loader_sec);
+ gdb::byte_vector loader_buf (loader_size);
+ if (!bfd_get_section_contents (abfd, loader_sec, loader_buf.data (),
+ 0, loader_size))
+ continue;
+
+ aix_tls_reloc_info ri
+ = rs6000_aix_find_tls_reloc (abfd,
+ candidate.data_section_offset (),
+ loader_buf, offset);
+ if (ri.rtype != -1)
+ return ri;
+ }
+
+ aix_tls_reloc_info empty;
+ return empty;
+}
+
+/* This is a function for TLS resolution for a variable in OBJFILE when no loader reloc
+ was found in the owning .so or in any other loaded module.
+
+ On AIX the R_TLSM (module-id) slot is sometimes left as zero by the loader,
+ so above functions cannot be used. As a final fallback an attempt to
+ resolve via the runtime __tls_get_addr mechanism:
+
+ 1. Verify __tls_get_addr is present which confirms TLS-capable runtime.
+ 2. Find any R_TLSM or R_TLSML slot in the owning .so that is non-zero and
+ use its module-id to walk the thread vector.
+ 3. If all R_TLSM/R_TLSML slots are zero (loader did not fill them), throw
+ TLS_NOT_ALLOCATED_YET_ERROR. */
+
+static CORE_ADDR
+rs6000_aix_compute_tls_address (struct objfile *objfile,
+ ULONGEST tp,
+ CORE_ADDR offset)
+{
+ if (lookup_minimal_symbol (current_program_space, "__tls_get_addr").minsym
+ == nullptr)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": "
+ "no loader relocation found and __tls_get_addr not "
+ "present in inferior"),
+ objfile_name (objfile));
+
+ bfd *abfd = objfile->obfd.get ();
+ asection *loader_sec = bfd_get_section_by_name (abfd, ".loader");
+ if (loader_sec == nullptr)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": no .loader section"),
+ objfile_name (objfile));
+
+ bfd_size_type loader_size = bfd_section_size (loader_sec);
+ gdb::byte_vector loader_buf (loader_size);
+ if (!bfd_get_section_contents (abfd, loader_sec, loader_buf.data (),
+ 0, loader_size))
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": cannot read .loader"),
+ objfile_name (objfile));
+
+ struct internal_ldhdr ldhdr;
+ bfd_xcoff_swap_ldhdr_in (abfd, loader_buf.data (), &ldhdr);
+
+ bfd_vma reloc_start = bfd_xcoff_loader_reloc_offset (abfd, &ldhdr);
+ bfd_size_type relsz = bfd_xcoff_ldrelsz (abfd);
+ CORE_ADDR data_slide = objfile->data_section_offset ();
+
+ const gdb_byte *reloc_ptr = loader_buf.data () + reloc_start;
+ for (size_t i = 0; i < ldhdr.l_nreloc; i++, reloc_ptr += relsz)
+ {
+ struct internal_ldrel ldrel;
+ bfd_xcoff_swap_ldrel_in (abfd, reloc_ptr, &ldrel);
+ int rt = ldrel.l_rtype & 0xff;
+ if (rt != XCOFF_R_TLSM && rt != XCOFF_R_TLSML)
+ continue;
+
+ CORE_ADDR modid_addr = ldrel.l_vaddr + data_slide;
+ uint64_t mod_id
+ = (uint64_t) rs6000_aix_read_tls_slot (modid_addr,
+ objfile_name (objfile));
+ if (mod_id == 0)
+ continue; /* loader left this slot empty */
+
+ CORE_ADDR tls_base = rs6000_aix_thread_vec_lookup (tp, mod_id,
+ objfile_name (objfile));
+ return tls_base + offset;
+ }
+
+ /* Every R_TLSM/R_TLSML slot is zero -- TLS has not been initialised yet. */
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS storage not yet allocated for \"%s\""),
+ objfile_name (objfile));
+}
+
+/* Scan the .loader section of OBJFILE and return TLS relocation information
+ for the variable with static symbol value SYM_OFFSET. Throws on hard
+ errors; returns an aix_tls_reloc_info with rtype == -1 if not found
+ (caller must decide what to do). */
+
+static aix_tls_reloc_info
+rs6000_aix_scan_loader (struct objfile *objfile, CORE_ADDR sym_offset)
+{
+ bfd *abfd = objfile->obfd.get ();
+
+ asection *loader_sec = bfd_get_section_by_name (abfd, ".loader");
+ if (loader_sec == nullptr)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": no .loader section"),
+ objfile_name (objfile));
+
+ bfd_size_type loader_size = bfd_section_size (loader_sec);
+ gdb::byte_vector loader_buf (loader_size);
+ if (!bfd_get_section_contents (abfd, loader_sec, loader_buf.data (),
+ 0, loader_size))
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": cannot read .loader"),
+ objfile_name (objfile));
+
+ {
+ struct internal_ldhdr ldhdr;
+ bfd_xcoff_swap_ldhdr_in (abfd, loader_buf.data (), &ldhdr);
+ bfd_vma reloc_start = bfd_xcoff_loader_reloc_offset (abfd, &ldhdr);
+ bfd_size_type relsz = bfd_xcoff_ldrelsz (abfd);
+ if (reloc_start + ldhdr.l_nreloc * relsz > loader_size)
+ throw_error (TLS_GENERIC_ERROR,
+ _("Cannot resolve TLS for \"%s\": "
+ ".loader section truncated"),
+ objfile_name (objfile));
+ }
+
+ return rs6000_aix_find_tls_reloc (abfd,
+ objfile->data_section_offset (),
+ loader_buf, sym_offset);
+}
+
+/* On 64-bit AIX the thread pointer (TP) is in R13. For variables in
the main executable (lm_addr == 0) the XCOFF symbol value is a
signed TP-relative offset baked in at link time:
address = tp + (int64_t) offset */
@@ -1405,8 +1812,88 @@ rs6000_aix_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
if (lm_addr == 0)
return tp + (CORE_ADDR)(int64_t) offset;
+ /* Shared-library models: lm_addr encodes the objfile pointer. */
+ struct objfile *objfile = (struct objfile *)(uintptr_t) lm_addr;
+ aix_tls_reloc_info ri = rs6000_aix_scan_loader (objfile, offset);
+
+ if (ri.rtype == -1)
+ {
+ /* No loader reloc in the owning .so. Search every other objfile
+ (typically the main exe has R_TLS_IE for cross-module vars). */
+ ri = rs6000_aix_scan_all_objfiles (offset);
+ if (ri.rtype == -1)
+ return rs6000_aix_compute_tls_address (objfile, tp, offset);
+ }
+
+ if (ri.rtype == XCOFF_R_TLS_IE)
+ {
+ /* initial-exec: tp + signed TP-relative offset from TOC slot. */
+ int64_t tp_offset = rs6000_aix_read_tls_slot (ri.toc_addr,
+ objfile_name (objfile));
+ if (tp_offset == 0)
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS storage not yet allocated for \"%s\""),
+ objfile_name (objfile));
+ return tp + (CORE_ADDR) tp_offset;
+ }
+
+ if (ri.rtype == XCOFF_R_TLS)
+ {
+ /* global-dynamic case only.
+ The AIX loader sometimes leaves R_TLSM as zero; in that case
+ TOC[R_TLS] itself holds the TP-relative offset (equivalent to
+ initial-exec), so use tp + toc_val as the fallback. */
+ if (ri.modid_toc_addr != 0)
+ {
+ uint64_t mod_id = (uint64_t) rs6000_aix_read_tls_slot (
+ ri.modid_toc_addr, objfile_name (objfile));
+ if (mod_id != 0)
+ {
+ int64_t var_offset = rs6000_aix_read_tls_slot (
+ ri.toc_addr, objfile_name (objfile));
+ CORE_ADDR tls_base = rs6000_aix_thread_vec_lookup (tp, mod_id,
+ objfile_name (objfile));
+ return tls_base + (CORE_ADDR) var_offset;
+ }
+ }
+
+ /* R_TLSM not found or zero: fall back to tp + TOC[R_TLS]. */
+ int64_t tp_offset = rs6000_aix_read_tls_slot (ri.toc_addr,
+ objfile_name (objfile));
+ if (tp_offset == 0)
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS storage not yet allocated for \"%s\""),
+ objfile_name (objfile));
+ return tp + (CORE_ADDR) tp_offset;
+ }
+
+ if (ri.rtype == XCOFF_R_TLS_LD)
+ {
+ /* local-dynamic: TOC[R_TLSML] holds the module-id. */
+ if (ri.modid_ld_addr != 0)
+ {
+ uint64_t mod_id = (uint64_t) rs6000_aix_read_tls_slot (
+ ri.modid_ld_addr, objfile_name (objfile));
+ if (mod_id != 0)
+ {
+ int64_t var_offset = rs6000_aix_read_tls_slot (
+ ri.toc_addr, objfile_name (objfile));
+ CORE_ADDR tls_base = rs6000_aix_thread_vec_lookup (tp, mod_id,
+ objfile_name (objfile));
+ return tls_base + (CORE_ADDR) var_offset;
+ }
+ }
+
+ /* R_TLSML is zero: last resort. */
+ return rs6000_aix_compute_tls_address (objfile, tp, offset);
+ }
+
+ /* R_TLS_LE in a shared library should not occur; the linker rejects it. */
throw_error (TLS_GENERIC_ERROR,
- _("TLS in shared libraries not yet supported on AIX"));
+ _("Cannot resolve TLS for \"%s\": "
+ "unexpected TLS relocation type 0x%x in shared library"),
+ objfile_name (objfile), ri.rtype);
+
}
static void
--
2.51.2
next reply other threads:[~2026-09-03 9:03 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-03 8:56 Aditya Vidyadhar Kamath [this message]
2026-09-03 15:29 ` Ulrich Weigand
2026-09-08 13:30 ` Aditya Kamath
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260903085614.39532-2-akamath996@gmail.com \
--to=akamath996@gmail.com \
--cc=Aditya.Kamath1@ibm.com \
--cc=gdb-patches@sourceware.org \
--cc=sangamesh.swamy@in.ibm.com \
--cc=simon.marchi@polymtl.ca \
--cc=tom@tromey.com \
--cc=ulrich.weigand@de.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox