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

Gedare Bloom gedare at rtems.org
Sat Aug 19 14:11:53 UTC 2023


ok

On Wed, Aug 16, 2023 at 9:00 PM <chrisj at rtems.org> wrote:
>
> 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
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list