[PATCH v2] libdl: Add support to import base image TLS symbols

chrisj at rtems.org chrisj at rtems.org
Thu Aug 17 03:00:28 UTC 2023


From: Chris Johns <chrisj at rtems.org>

This change requires an rtems-tools update for symbol generation.

Working architectures:
 - aarch64
 - arm
 - powerpc
 - sparc

No newlib TLS support but checked:
 - i386
 - m69k

Updates #4920
---
 cpukit/include/rtems/rtl/rtl-sym.h |  26 ++++-
 cpukit/include/rtems/rtl/rtl.h     |   8 +-
 cpukit/libdl/rtl-elf.c             |  20 +++-
 cpukit/libdl/rtl-mdreloc-aarch64.c |   6 +-
 cpukit/libdl/rtl-mdreloc-arm.c     |   3 +-
 cpukit/libdl/rtl-mdreloc-powerpc.c |  18 +++-
 cpukit/libdl/rtl-mdreloc-sparc.c   | 154 ++++++++++++++++++++++++-----
 cpukit/libdl/rtl-sym.c             |  40 ++++++--
 cpukit/libdl/rtl-tls.c             | 114 +++++++++++++++++++++
 cpukit/libdl/rtl-tls.h             |  51 ++++++++++
 cpukit/libdl/rtl.c                 |   8 +-
 spec/build/cpukit/objdl.yml        |   1 +
 testsuites/libtests/dl11/dl-load.c |  27 ++++-
 13 files changed, 418 insertions(+), 58 deletions(-)
 create mode 100644 cpukit/libdl/rtl-tls.c
 create mode 100644 cpukit/libdl/rtl-tls.h

diff --git a/cpukit/include/rtems/rtl/rtl-sym.h b/cpukit/include/rtems/rtl/rtl-sym.h
index 0d29a6ae40..3502b303b8 100644
--- a/cpukit/include/rtems/rtl/rtl-sym.h
+++ b/cpukit/include/rtems/rtl/rtl-sym.h
@@ -62,6 +62,22 @@ typedef struct rtems_rtl_symbols
   size_t               nbuckets;
 } rtems_rtl_symbols;
 
+/**
+ * A TLS variable offset call. There is one per base image TLS
+ * variable.
+ */
+typedef size_t (*rtems_rtl_tls_offset_func)(void);
+
+/**
+ * A TLS symbol offset entry. It is used with an exported symbol table
+ * to find a TSL table offset for a variable at runtime.
+ */
+typedef struct rtems_rtl_tls_offset
+{
+  size_t                    index;  /** exported symbol table index */
+  rtems_rtl_tls_offset_func offset; /** TLS offset function */
+} rtems_rtl_tls_offset;
+
 /**
  * Open a symbol table with the specified number of buckets.
  *
@@ -101,10 +117,14 @@ void rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols);
  * @param obj The object table the symbols are for.
  * @param esyms The exported symbol table.
  * @param size The size of the table in bytes.
+ * @param tls_offsets The TLS offsets table. If NULL none provided.
+ * @param tls_size The number TLS offset entries in the table.
  */
-bool rtems_rtl_symbol_global_add (rtems_rtl_obj*       obj,
-                                  const unsigned char* esyms,
-                                  unsigned int         size);
+bool rtems_rtl_symbol_global_add (rtems_rtl_obj*        obj,
+                                  const unsigned char*  esyms,
+                                  unsigned int          size,
+                                  rtems_rtl_tls_offset* tls_offsets,
+                                  unsigned int          tls_size);
 
 /**
  * Find a symbol given the symbol label in the global symbol table.
diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h
index 0fd4e74cdf..bd3dce588a 100644
--- a/cpukit/include/rtems/rtl/rtl.h
+++ b/cpukit/include/rtems/rtl/rtl.h
@@ -393,9 +393,13 @@ bool rtems_rtl_path_prepend (const char* path);
  *
  * @param esyms The exported symbol table.
  * @param count The size of the exported symbol table.
+ * @param tls_offsets The TLS offsets table. If NULL none provided.
+ * @param tls_size The number TLS offset entries in the table.
  */
-void rtems_rtl_base_sym_global_add (const unsigned char* esyms,
-                                    unsigned int         count);
+void rtems_rtl_base_sym_global_add (const unsigned char*  esyms,
+                                    unsigned int          count,
+                                    rtems_rtl_tls_offset* tls_offsets,
+                                    unsigned int          tls_size);
 
 /**
  * Return the object file descriptor for the base image. The object file
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 5754070518..b46d2ac3a0 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -178,12 +178,19 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj*      obj,
 
   /*
    * If the symbol type is STT_NOTYPE the symbol references a global
-   * symbol. The gobal symbol table is searched to find it and that value
+   * symbol. The global symbol table is searched to find it and that value
    * returned. If the symbol is local to the object module the section for the
    * symbol is located and it's base added to the symbol's value giving an
    * absolute location.
+   *
+   * If the symbols type of TLS return the symbols value. It is the
+   * offset from the thread's TLS area base. The offset is set by the
+   * linker for the base image and by the TLS allocator for loaded
+   * modules. There is no section and no absolute base.
    */
-  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE || sym->st_shndx == SHN_COMMON)
+  if (ELF_ST_TYPE (sym->st_info) == STT_NOTYPE ||
+      sym->st_shndx == SHN_COMMON ||
+      ELF_ST_TYPE (sym->st_info) == STT_TLS)
   {
     /*
      * Search the object file then the global table for the symbol.
@@ -246,6 +253,13 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj*      obj,
   rtems_rtl_word            rel_words[3];
   rtems_rtl_elf_rel_status  rs;
 
+  /*
+   * TLS are not parsed.
+   */
+  if (ELF_ST_TYPE (sym->st_info) == STT_TLS) {
+    return true;
+  }
+
   /*
    * Check the reloc record to see if a trampoline is needed.
    */
@@ -302,7 +316,7 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj*      obj,
      * Find the symbol's object file. It cannot be NULL so ignore that result
      * if returned, it means something is corrupted. We are in an iterator.
      */
-    rtems_rtl_obj*  sobj = rtems_rtl_find_obj_with_symbol (symbol);
+    rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol);
     if (sobj != NULL)
     {
       /*
diff --git a/cpukit/libdl/rtl-mdreloc-aarch64.c b/cpukit/libdl/rtl-mdreloc-aarch64.c
index 15396c3de9..3b808f6667 100644
--- a/cpukit/libdl/rtl-mdreloc-aarch64.c
+++ b/cpukit/libdl/rtl-mdreloc-aarch64.c
@@ -309,11 +309,7 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
       }
 
       if (!parsing) {
-        target = (Elf_Addr)symvalue + rela->r_addend;
-	/* Calculate offset accounting for the DTV */
-	target -= (uintptr_t)_TLS_Data_begin;
-	target += sizeof(TLS_Dynamic_thread_vector);
-
+        target = (Elf_Addr)symvalue;
         target >>= shift;
 	target &= WIDTHMASK(12);
         if (of_check && target >= of_check) {
diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c
index fbfd42dc58..b45708dd46 100644
--- a/cpukit/libdl/rtl-mdreloc-arm.c
+++ b/cpukit/libdl/rtl-mdreloc-arm.c
@@ -526,7 +526,6 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
       break;
 
     case R_TYPE(TLS_LE32):
-#if ALLOW_UNTESTED_RELOCS
       if (!parsing) {
         addend = *where;
         *where = symvalue + addend;
@@ -535,7 +534,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
                   (void *)*where, where, rtems_rtl_obj_oname (obj));
       }
       break;
-#endif
+
     case R_TYPE(TLS_GD32):
     case R_TYPE(TLS_LDM32):
     case R_TYPE(TLS_LDO32):
diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c
index c6062c872a..49ed9e848c 100644
--- a/cpukit/libdl/rtl-mdreloc-powerpc.c
+++ b/cpukit/libdl/rtl-mdreloc-powerpc.c
@@ -348,37 +348,47 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
       break;
 
     case R_TYPE(16_HA):
+    case R_TYPE(TPREL16_HA):
       /*
        * value:6; Field:half16; Expression: #ha(S+A)
+       * value:72; Field:half16; Expression: #ha(S+A)
        */
       if (!parsing) {
         tmp = symvalue + rela->r_addend;
         *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: 16_HA %p @ %p in %s\n",
+          printf ("rtl: %s16_HA %p @ %p in %s\n",
+                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HA) ? "TPREL" : "",
                   (void *)*(where), where, rtems_rtl_obj_oname (obj));
       }
       break;
 
     case R_TYPE(16_HI):
+    case R_TYPE(TPREL16_HI):
       /*
        * value:5; Field:half16; Expression: #hi(S+A)
+       * value:71; Field:half16; Expression: #hi(S+A)
        */
       if (!parsing) {
         *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: 16_HI %p @ %p in %s\n",
+          printf ("rtl: %s16_HI %p @ %p in %s\n",
+                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HI) ? "TPREL" : "",
                   (void *)*where, where, rtems_rtl_obj_oname (obj));
       }
       break;
+
     case R_TYPE(16_LO):
+    case R_TYPE(TPREL16_LO):
       /*
        * value:4; Field:half16; Expression: #lo(S+A)
+       * value:71; Field:half16; Expression: #lo(S+A)
        */
       if (!parsing) {
         *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: 16_LO %p @ %p in %s\n",
+          printf ("rtl: %s16_LO %p @ %p in %s\n",
+                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_LO) ? "TPREL" : "",
                   (void *)*where, where, rtems_rtl_obj_oname (obj));
       }
       break;
@@ -484,7 +494,7 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
               (void *)rela->r_offset, (void *)*where);
       rtems_rtl_set_error (EINVAL,
                            "%s: Unsupported relocation type %" PRId32
-                           "in non-PLT relocations",
+                           " in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
       return rtems_rtl_elf_rel_failure;
   }
diff --git a/cpukit/libdl/rtl-mdreloc-sparc.c b/cpukit/libdl/rtl-mdreloc-sparc.c
index f8a4312a8a..7dd8a2af2f 100644
--- a/cpukit/libdl/rtl-mdreloc-sparc.c
+++ b/cpukit/libdl/rtl-mdreloc-sparc.c
@@ -87,46 +87,66 @@ static const uint32_t reloc_target_flags[] = {
   _RF_G|              _RF_SZ(32) | _RF_RS(10),   /* GOT22 */
   _RF_S|_RF_A|_RF_P|  _RF_SZ(32) | _RF_RS(0),    /* PC10 */
   _RF_S|_RF_A|_RF_P|  _RF_SZ(32) | _RF_RS(10),   /* PC22 */
-        _RF_A|_RF_P|  _RF_SZ(32) | _RF_RS(2),    /* WPLT30 */
-                      _RF_SZ(32) | _RF_RS(0),    /* COPY */
+  _RF_A|_RF_P|        _RF_SZ(32) | _RF_RS(2),    /* WPLT30 */
+  _RF_SZ(32) |                     _RF_RS(0),    /* COPY */
   _RF_S|_RF_A|        _RF_SZ(32) | _RF_RS(0),    /* GLOB_DAT */
-                      _RF_SZ(32) | _RF_RS(0),    /* JMP_SLOT */
-        _RF_A|  _RF_B|_RF_SZ(32) | _RF_RS(0),    /* RELATIVE */
-  _RF_S|_RF_A|  _RF_U|_RF_SZ(32) | _RF_RS(0),    /* UA_32 */
+  _RF_SZ(32) |                     _RF_RS(0),    /* JMP_SLOT */
+  _RF_A|  _RF_B|      _RF_SZ(32) | _RF_RS(0),    /* RELATIVE */
+  _RF_S|_RF_A|_RF_U|  _RF_SZ(32) | _RF_RS(0),    /* UA_32 */
+
+  /* TLS and 64 bit relocs not listed here... */
 };
+#define RELOC_TARGET_FLAGS_SIZE \
+  (sizeof(reloc_target_flags) / sizeof(reloc_target_flags[0]))
 
-#define NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL
-#ifdef NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL
+#define RTLD_DEBUG_RELOC
+#ifdef RTLD_DEBUG_RELOC
 static const char *reloc_names[] = {
   "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8",
   "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22",
   "22", "13", "LO10", "GOT10", "GOT13",
   "GOT22", "PC10", "PC22", "WPLT30", "COPY",
-  "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32"
+  "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32",
+
+  /* not used with 32bit userland, besides a few of the TLS ones */
+  "PLT32",
+  "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32",
+  "10", "11", "64", "OLO10", "HH22",
+  "HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22",
+  "WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6",
+  "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44",
+  "L44", "REGISTER", "UA64", "UA16",
+  "TLS_GD_HI22", "TLS_GD_LO10", "TLS_GD_ADD", "TLS_GD_CALL",
+  "TLS_LDM_HI22", "TLS_LDM_LO10", "TLS_LDM_ADD", "TLS_LDM_CALL",
+  "TLS_LDO_HIX22", "TLS_LDO_LOX10", "TLS_LDO_ADD", "TLS_IE_HI22",
+  "TLS_IE_LO10", "TLS_IE_LD", "TLS_IE_LDX", "TLS_IE_ADD", "TLS_LE_HIX22",
+  "TLS_LE_LOX10", "TLS_DTPMOD32", "TLS_DTPMOD64", "TLS_DTPOFF32",
+  "TLS_DTPOFF64", "TLS_TPOFF32", "TLS_TPOFF64",
 };
 #endif
 
-#define RELOC_RESOLVE_SYMBOL(t)    ((reloc_target_flags[t] & _RF_S) != 0)
-#define RELOC_PC_RELATIVE(t)       ((reloc_target_flags[t] & _RF_P) != 0)
-#define RELOC_BASE_RELATIVE(t)     ((reloc_target_flags[t] & _RF_B) != 0)
-#define RELOC_UNALIGNED(t)         ((reloc_target_flags[t] & _RF_U) != 0)
-#define RELOC_USE_ADDEND(t)        ((reloc_target_flags[t] & _RF_A) != 0)
-#define RELOC_TARGET_SIZE(t)       ((reloc_target_flags[t] >> 8) & 0xff)
-#define RELOC_VALUE_RIGHTSHIFT(t)  (reloc_target_flags[t] & 0xff)
+#define RELOC_RESOLVE_SYMBOL(t)         ((reloc_target_flags[t] & _RF_S) != 0)
+#define RELOC_PC_RELATIVE(t)            ((reloc_target_flags[t] & _RF_P) != 0)
+#define RELOC_BASE_RELATIVE(t)          ((reloc_target_flags[t] & _RF_B) != 0)
+#define RELOC_UNALIGNED(t)              ((reloc_target_flags[t] & _RF_U) != 0)
+#define RELOC_USE_ADDEND(t)             ((reloc_target_flags[t] & _RF_A) != 0)
+#define RELOC_TARGET_SIZE(t)            ((reloc_target_flags[t] >> 8) & 0xff)
+#define RELOC_VALUE_RIGHTSHIFT(t)       (reloc_target_flags[t] & 0xff)
+#define RELOC_TLS(t)                    (t >= R_TYPE(TLS_GD_HI22))
 
 static const int reloc_target_bitmask[] = {
 #define _BM(x)  (~(-(1ULL << (x))))
-  0,        /* NONE */
-  _BM(8),  _BM(16), _BM(32),  /* RELOC_8, _16, _32 */
-  _BM(8),  _BM(16), _BM(32),  /* DISP8, DISP16, DISP32 */
-  _BM(30), _BM(22),           /* WDISP30, WDISP22 */
-  _BM(22), _BM(22),           /* HI22, _22 */
-  _BM(13), _BM(10),           /* RELOC_13, _LO10 */
-  _BM(10), _BM(13), _BM(22),  /* GOT10, GOT13, GOT22 */
-  _BM(10), _BM(22),           /* _PC10, _PC22 */
-  _BM(30), 0,                 /* _WPLT30, _COPY */
-  -1, -1, -1,                 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
-  _BM(32)                     /* _UA32 */
+  0,                            /* NONE */
+  _BM(8), _BM(16), _BM(32),     /* RELOC_8, _16, _32 */
+  _BM(8), _BM(16), _BM(32),     /* DISP8, DISP16, DISP32 */
+  _BM(30), _BM(22),             /* WDISP30, WDISP22 */
+  _BM(22), _BM(22),             /* HI22, _22 */
+  _BM(13), _BM(10),             /* RELOC_13, _LO10 */
+  _BM(10), _BM(13), _BM(22),    /* GOT10, GOT13, GOT22 */
+  _BM(10), _BM(22),             /* _PC10, _PC22 */
+  _BM(30), 0,                   /* _WPLT30, _COPY */
+  -1, -1, -1,                   /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
+  _BM(32)                       /* _UA32 */
 #undef _BM
 };
 #define RELOC_VALUE_BITMASK(t)  (reloc_target_bitmask[t])
@@ -173,7 +193,20 @@ rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
 {
-  return RELOC_RESOLVE_SYMBOL (type) ? true : false;
+  bool r = false;
+  if (type < RELOC_TARGET_FLAGS_SIZE) {
+    r = RELOC_RESOLVE_SYMBOL (type) ? true : false;
+  }
+  switch (type) {
+    case R_TYPE(TLS_DTPOFF32):
+    case R_TYPE(TLS_LE_HIX22):
+    case R_TYPE(TLS_LE_LOX10):
+      r = true;
+      break;
+  default:
+    break;
+  }
+  return r;
 }
 
 size_t
@@ -240,6 +273,73 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
 
   value = rela->r_addend;
 
+  /*
+   * Handle TLS relocations here, they are different.
+   */
+  if (RELOC_TLS(type)) {
+    switch (type) {
+    case R_TYPE(TLS_DTPMOD32):
+      #if NETBSD_CODE__NOT_USED
+      *where = (Elf_Addr)defobj->tlsindex;
+      #endif
+
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: TLS_DTPMOD32 %s in %s --> %p\n",
+               symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      break;
+
+    case R_TYPE(TLS_DTPOFF32):
+      *where = (Elf_Addr)(symvalue + rela->r_addend);
+
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: TLS_DTPOFF32 %s in %s --> %p\n",
+               symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      break;
+
+    case R_TYPE(TLS_TPOFF32):
+      #if NETBSD_CODE__NOT_USED
+      if (!defobj->tls_static &&
+          _rtld_tls_offset_allocate(__UNCONST(defobj)))
+        return ;
+
+      *where = (Elf_Addr)(def->st_value -
+                          defobj->tlsoffset + rela->r_addend);
+     #endif
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: TLS_TPOFF32 %s in %s --> %p\n",
+               symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      return rtems_rtl_elf_rel_failure;
+
+    case R_TYPE(TLS_LE_HIX22):
+      *where |= ((symvalue + rela->r_addend) ^ 0xffffffff) >> 10;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: R_SPARC_TLS_LE_HIX22 %s in %s --> %p\n",
+               symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      break;
+
+    case R_TYPE(TLS_LE_LOX10):
+      *where |= ((symvalue + rela->r_addend) & 0x3ff) | 0x1c00;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: R_SPARC_TLS_LE_LOX10 %s in %s --> %p\n",
+               symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      break;
+
+    default:
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf("rtl: reloc: unknown TLS relo: %d for %s in %s --> %p\n",
+               type, symname, rtems_rtl_obj_oname (obj), (void *)*where);
+      return rtems_rtl_elf_rel_failure;
+    }
+    return rtems_rtl_elf_rel_no_error;
+  }
+
+  /*
+   * If it is no TLS relocation (handled above), we can not
+   * deal with it if it is beyond R_SPARC_6.
+   */
+  if (type > R_TYPE(6))
+    return rtems_rtl_elf_rel_failure;
+
   /*
    * Handle relative relocs here, as an optimization.
    */
diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c
index 5c9c3981df..bd203fd158 100644
--- a/cpukit/libdl/rtl-sym.c
+++ b/cpukit/libdl/rtl-sym.c
@@ -77,6 +77,22 @@ rtems_rtl_symbol_global_insert (rtems_rtl_symbols* symbols,
                       &symbol->node);
 }
 
+static rtems_rtl_tls_offset*
+rtems_rtl_symbol_find_tls_offset (size_t                index,
+                                  rtems_rtl_tls_offset* tls_offsets,
+                                  size_t                tls_size)
+{
+  size_t entry;
+  for (entry = 0; entry < tls_size; ++entry)
+  {
+    if (tls_offsets[entry].index == index)
+    {
+      return &tls_offsets[entry];
+    }
+  }
+  return NULL;
+}
+
 bool
 rtems_rtl_symbol_table_open (rtems_rtl_symbols* symbols,
                              size_t             buckets)
@@ -103,9 +119,11 @@ rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols)
 }
 
 bool
-rtems_rtl_symbol_global_add (rtems_rtl_obj*       obj,
-                             const unsigned char* esyms,
-                             unsigned int         size)
+rtems_rtl_symbol_global_add (rtems_rtl_obj*        obj,
+                             const unsigned char*  esyms,
+                             unsigned int          size,
+                             rtems_rtl_tls_offset* tls_offsets,
+                             unsigned int          tls_size)
 {
   rtems_rtl_symbols* symbols;
   rtems_rtl_obj_sym* sym;
@@ -159,6 +177,9 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj*       obj,
 
   symbols = rtems_rtl_global_symbols ();
 
+  obj->global_syms = count;
+
+  count = 0;
   s = 0;
   sym = obj->global_table;
 
@@ -171,24 +192,29 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj*       obj,
      */
     union {
       uint8_t data[sizeof (void*)];
-      void*   value;
+      void*   voidp;
     } copy_voidp;
+    rtems_rtl_tls_offset* tls_off;
     int b;
 
     sym->name = (const char*) &esyms[s];
     s += strlen (sym->name) + 1;
     for (b = 0; b < sizeof (void*); ++b, ++s)
       copy_voidp.data[b] = esyms[s];
-    sym->value = copy_voidp.value;
+    tls_off = rtems_rtl_symbol_find_tls_offset (count, tls_offsets, tls_size);
+    if (tls_off == NULL) {
+      sym->value = copy_voidp.voidp;
+    } else {
+      sym->value = (void*) tls_off->offset();
+    }
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
       printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value);
     if (rtems_rtl_symbol_global_find (sym->name) == NULL)
       rtems_rtl_symbol_global_insert (symbols, sym);
+    ++count;
     ++sym;
   }
 
-  obj->global_syms = count;
-
   return true;
 }
 
diff --git a/cpukit/libdl/rtl-tls.c b/cpukit/libdl/rtl-tls.c
new file mode 100644
index 0000000000..0b940c270b
--- /dev/null
+++ b/cpukit/libdl/rtl-tls.c
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup rtems_rtld
+ *
+ * @brief RTEMS Run-Time Link Editor Thread Local Storage
+ *
+ * TLS support the RTL.
+ */
+
+/*
+ *  COPYRIGHT (c) 2023 Chris Johns <chrisj at rtems.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rtl-tls.h"
+
+/*
+ * The cpukit/score should provide a call for any arch that
+ * supports TLS. This code is here until that happens if it
+ * happens.
+ */
+
+/*
+ * Pasted in from:
+ *
+ * https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/platform/bionic/tls.h
+ *
+ * Note, "#pragma once" has been removed
+ */
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#if defined(__aarch64__)
+# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
+#elif defined(__arm__)
+# define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; })
+#elif defined(__i386__)
+# define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; })
+#elif defined(__riscv)
+# define __get_tls() ({ void** __val; __asm__("mv %0, tp" : "=r"(__val)); __val; })
+#elif defined(__x86_64__)
+# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
+#elif defined(__sparc__)
+#include <stdint.h>
+# define __get_tls() ({ void** __val; register uintptr_t g7 __asm__( "g7" ); __val = (void**) g7; __val; })
+#elif defined(__powerpc__)
+#include <stdint.h>
+# define __get_tls() ({ void** __val; register uintptr_t tp __asm__( "2" ); __val = (void**) tp; __val; })
+#elif defined(__m68k__) || defined(__v850__)
+/* No TLS support */
+# define __get_tls() (void*) 0UL
+#else
+#error unsupported architecture
+#endif
+
+#if defined(__get_tls)
+
+void* rtems_rtl_tls_get_base (void)
+{
+  return (void*) __get_tls();
+}
+
+#endif
diff --git a/cpukit/libdl/rtl-tls.h b/cpukit/libdl/rtl-tls.h
new file mode 100644
index 0000000000..78dc738dd4
--- /dev/null
+++ b/cpukit/libdl/rtl-tls.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup rtems_rtld
+ *
+ * @brief RTEMS Run-Time Link Editor Thread Local Storage
+ *
+ * TLS support the RTL.
+ */
+
+/*
+ *  COPYRIGHT (c) 2023 Chris Johns <chrisj at rtems.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined (_RTEMS_RTL_TLS_H_)
+#define _RTEMS_RTL_TLS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void* rtems_rtl_tls_get_base (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index 21ddb00aac..8250af24c9 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -857,8 +857,10 @@ rtems_rtl_path_prepend (const char* path)
 }
 
 void
-rtems_rtl_base_sym_global_add (const unsigned char* esyms,
-                               unsigned int         size)
+rtems_rtl_base_sym_global_add (const unsigned char*  esyms,
+                               unsigned int          size,
+                               rtems_rtl_tls_offset* tls_offsets,
+                               unsigned int          tls_size)
 {
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
     printf ("rtl: adding global symbols, table size %u\n", size);
@@ -869,7 +871,7 @@ rtems_rtl_base_sym_global_add (const unsigned char* esyms,
     return;
   }
 
-  rtems_rtl_symbol_global_add (rtl->base, esyms, size);
+  rtems_rtl_symbol_global_add (rtl->base, esyms, size, tls_offsets, tls_size);
 
   rtems_rtl_unlock ();
 }
diff --git a/spec/build/cpukit/objdl.yml b/spec/build/cpukit/objdl.yml
index 133485a93d..f6dc9478a6 100644
--- a/spec/build/cpukit/objdl.yml
+++ b/spec/build/cpukit/objdl.yml
@@ -66,6 +66,7 @@ source:
 - cpukit/libdl/rtl-shell.c
 - cpukit/libdl/rtl-string.c
 - cpukit/libdl/rtl-sym.c
+- cpukit/libdl/rtl-tls.c
 - cpukit/libdl/rtl-trace.c
 - cpukit/libdl/rtl-unresolved.c
 - cpukit/libdl/rtl-unwind-dw2.c
diff --git a/testsuites/libtests/dl11/dl-load.c b/testsuites/libtests/dl11/dl-load.c
index aee1517269..70d7bf1c65 100644
--- a/testsuites/libtests/dl11/dl-load.c
+++ b/testsuites/libtests/dl11/dl-load.c
@@ -37,10 +37,17 @@
 
 #define TEST_TRACE 0
 #if TEST_TRACE
+ #define SHOW_GLOBAL_SYMS 1
+ #if SHOW_GLOBAL_SYMS
+  #define TRACE_GLOBAL_SYMBOL RTEMS_RTL_TRACE_GLOBAL_SYM
+ #else
+  #define TRACE_GLOBAL_SYMBOL 0
+ #endif
  #define DEBUG_TRACE (RTEMS_RTL_TRACE_DETAIL | \
                       RTEMS_RTL_TRACE_WARNING | \
                       RTEMS_RTL_TRACE_LOAD | \
                       RTEMS_RTL_TRACE_UNLOAD | \
+                      TRACE_GLOBAL_SYMBOL | \
                       RTEMS_RTL_TRACE_SYMBOL | \
                       RTEMS_RTL_TRACE_RELOC | \
                       RTEMS_RTL_TRACE_ALLOCATOR | \
@@ -69,6 +76,9 @@ static void dl_load_dump (void)
 typedef int (*int_call_t)(void);
 typedef int* (*ptr_call_t)(void);
 
+void* get_errno_ptr(void);
+int get_errno(void);
+
 int dl_load_test(void)
 {
   void*  handle;
@@ -116,7 +126,7 @@ int dl_load_test(void)
   }
 
   ptr_call_ret = ptr_call ();
-  if (ptr_call_ret != &errno)
+  if (ptr_call_ret != get_errno_ptr())
   {
     printf("dlsym ptr_call failed: ret value bad\n");
     return 1;
@@ -124,7 +134,7 @@ int dl_load_test(void)
 
   errno = 12345;
   int_call_ret = int_call ();
-  if (int_call_ret != 12345)
+  if (int_call_ret != get_errno())
   {
     printf("dlsym int_call failed: ret value bad\n");
     return 1;
@@ -140,3 +150,16 @@ int dl_load_test(void)
 
   return 0;
 }
+
+/*
+ * Disasseble these to see how the platform accesses TLS
+ */
+void* get_errno_ptr(void)
+{
+  return &errno;
+}
+
+int get_errno(void)
+{
+  return errno;
+}
-- 
2.37.1



More information about the devel mailing list