This change implements Xtensa FDPIC ABI as specified in the first
version of the following document:

 https://github.com/jcmvbkbc/xtensa-abi/blob/master/fdpic-xtensa.txt

Signed-off-by: Max Filippov <jcmvb...@gmail.com>
---
The toolchain components matching the libc are available in
the following repositories with the tag xtensa-fdpic-abi-spec-1.4:

 https://github.com/jcmvbkbc/binutils-gdb-xtensa/tree/xtensa-fdpic-abi-spec-1.4
 https://github.com/jcmvbkbc/gcc-xtensa/tree/xtensa-fdpic-abi-spec-1.4

---
Changes v1->v2:

- add missing ';' after FDPIC_LOAD_JUMPTARGET in the SYSCALL_ERROR_HANDLER
  It suppressed the following callx instruction resulting in occasional
  crashes on error return from certain syscalls
- add -DUSE___THREAD to ASFLAGS in nptl/.../xtensa/Makefile.arch to
  generate direct access to errno in assembly code using
  SYSCALL_ERROR_HANDLER
- drop patch 2 from the series

---
 Rules.mak                                     |   4 +
 extra/Configs/Config.in                       |   2 +-
 extra/Configs/Config.in.arch                  |   2 +-
 include/elf.h                                 |   6 +-
 ldso/ldso/xtensa/dl-inlines.h                 |   1 +
 ldso/ldso/xtensa/dl-startup.h                 |  91 +++++++++++++-
 ldso/ldso/xtensa/dl-sysdep.h                  |  66 +++++++++-
 ldso/ldso/xtensa/dl-tlsdesc.S                 |  10 +-
 ldso/ldso/xtensa/elfinterp.c                  | 114 +++++++++++++----
 libc/sysdeps/linux/xtensa/__start_context.S   |   6 +-
 libc/sysdeps/linux/xtensa/bits/elf-fdpic.h    | 117 ++++++++++++++++++
 libc/sysdeps/linux/xtensa/clone.S             |   6 +
 libc/sysdeps/linux/xtensa/crt1.S              |  81 ++++++++++++
 libc/sysdeps/linux/xtensa/crti.S              |   8 ++
 libc/sysdeps/linux/xtensa/crtn.S              |   6 +
 libc/sysdeps/linux/xtensa/crtreloc.c          | 105 ++++++++++++++++
 libc/sysdeps/linux/xtensa/getcontext.S        |   1 +
 libc/sysdeps/linux/xtensa/makecontext.c       |   5 +
 libc/sysdeps/linux/xtensa/setcontext.S        |   1 +
 libc/sysdeps/linux/xtensa/setjmp.S            |   3 +-
 libc/sysdeps/linux/xtensa/swapcontext.S       |   1 +
 libc/sysdeps/linux/xtensa/sysdep.h            |  48 ++++++-
 .../unix/sysv/linux/xtensa/Makefile.arch      |   2 +
 libpthread/nptl/sysdeps/xtensa/dl-tls.h       |  33 +++--
 24 files changed, 673 insertions(+), 46 deletions(-)
 create mode 100644 ldso/ldso/xtensa/dl-inlines.h
 create mode 100644 libc/sysdeps/linux/xtensa/bits/elf-fdpic.h
 create mode 100644 libc/sysdeps/linux/xtensa/crtreloc.c

diff --git a/Rules.mak b/Rules.mak
index 5be74b86edd4..70d681238b24 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -520,6 +520,10 @@ ifeq ($(TARGET_ARCH),c6x)
        CPU_LDFLAGS-y += $(CPU_CFLAGS)
 endif
 
+ifeq ($(TARGET_ARCH),xtensa)
+       CPU_CFLAGS-$(UCLIBC_FORMAT_FDPIC_ELF) += -mfdpic
+endif
+
 $(eval $(call check-gcc-var,$(PIEFLAG_NAME)))
 PIEFLAG := $(CFLAG_$(PIEFLAG_NAME))
 ifeq ($(PIEFLAG),)
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 3a0136c99628..b2501a4da327 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -615,7 +615,7 @@ config UCLIBC_HAS_THREADS_NATIVE
                   !TARGET_h8300 && \
                   !TARGET_hppa && \
                   !TARGET_ia64 && \
-                  (ARCH_USE_MMU || TARGET_arm)
+                  (ARCH_USE_MMU || TARGET_arm || TARGET_xtensa)
        help
          If you want to compile uClibc with NPTL support, then answer Y.
 
diff --git a/extra/Configs/Config.in.arch b/extra/Configs/Config.in.arch
index 1ae5134b9df5..c13497893414 100644
--- a/extra/Configs/Config.in.arch
+++ b/extra/Configs/Config.in.arch
@@ -20,7 +20,7 @@ config UCLIBC_FORMAT_ELF
        select HAVE_LDSO
 config UCLIBC_FORMAT_FDPIC_ELF
        bool "FDPIC ELF"
-       depends on !ARCH_USE_MMU && (TARGET_bfin || TARGET_frv || TARGET_arm)
+       depends on !ARCH_USE_MMU && (TARGET_bfin || TARGET_frv || TARGET_arm || 
TARGET_xtensa)
        select DOPIC
 config UCLIBC_FORMAT_DSBT_ELF
        bool "DBST ELF"
diff --git a/include/elf.h b/include/elf.h
index c2efa9978677..1e7c89615a44 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -3588,8 +3588,12 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_XTENSA_TLSDESC_FN    50
 #define R_XTENSA_TLSDESC_ARG   51
 #define R_XTENSA_TLS_TPOFF     53
+#define R_XTENSA_SYM32         63
+#define R_XTENSA_FUNCDESC      68
+#define R_XTENSA_FUNCDESC_VALUE        69
+#define R_XTENSA_TLSDESC       72
 /* Keep this the last entry.  */
-#define R_XTENSA_NUM           54
+#define R_XTENSA_NUM           77
 
 /* C6X specific relocs */
 #define R_C6000_NONE           0
diff --git a/ldso/ldso/xtensa/dl-inlines.h b/ldso/ldso/xtensa/dl-inlines.h
new file mode 100644
index 000000000000..8fdf6eb48679
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-inlines.h
@@ -0,0 +1 @@
+#include "../fdpic/dl-inlines.h"
diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h
index c9350c0f201e..2a453752acaf 100644
--- a/ldso/ldso/xtensa/dl-startup.h
+++ b/ldso/ldso/xtensa/dl-startup.h
@@ -7,6 +7,68 @@
  * Parts taken from glibc/sysdeps/xtensa/dl-machine.h.
  */
 
+#if defined(__FDPIC__)
+__asm__ (
+    "  .text\n"
+    "  .align  4\n"
+    "   .literal_position\n"
+    "  .global _start\n"
+    "  .type   _start, @function\n"
+    "  .hidden _start\n"
+    "_start:\n"
+    "  .begin  no-transform\n"
+    "  _call0  1f\n"
+    "2:\n"
+    "  .end    no-transform\n"
+    "  .align  4\n"
+    "1:\n"
+#if defined(__XTENSA_CALL0_ABI__)
+    "  movi    a15, 2b\n"
+    "  sub     a15, a0, a15\n"
+
+    /* Save FDPIC pointers in callee-saved registers */
+    "  mov     a12, a4\n"
+    "  mov     a13, a5\n"
+    "  mov     a14, a6\n"
+
+    /* Call __self_reloc */
+    "  mov     a2, a5\n"
+    "  movi    a3, __ROFIXUP_LIST__\n"
+    "  add     a3, a3, a15\n"
+    "  movi    a4, __ROFIXUP_END__\n"
+    "  add     a4, a4, a15\n"
+    "  movi    a0, __self_reloc\n"
+    "  add     a0, a0, a15\n"
+    "  callx0  a0\n"
+
+    /* call _dl_start */
+    "  mov     a3, a12\n"
+    "  mov     a4, a13\n"
+    "  mov     a5, a14\n"
+    "  mov     a7, sp\n"
+    "  addi    sp, sp, -16\n"
+    "  mov     a6, sp\n"
+    "  mov     a11, a2\n"
+    /* a13, interpreter map is no longer needed, save interpreter GOT there */
+    "  mov     a13, a2\n"
+    "  movi    a0, _dl_start\n"
+    "  add     a0, a0, a15\n"
+    "  callx0  a0\n"
+
+    /* call main */
+    "  l32i    a0, sp, 0\n"
+    "  l32i    a11, sp, 4\n"
+    "  addi    sp, sp, 16\n"
+    "  mov     a4, a12\n"
+    "  movi    a5, _dl_fini@GOTOFFFUNCDESC\n"
+    "  add     a5, a5, a13\n"
+    "  mov     a6, a14\n"
+    "  jx      a0\n"
+#else
+#error Unsupported Xtensa ABI
+#endif
+   );
+#else /* __FDPIC__ */
 #ifndef L_rcrt1
 __asm__ (
     "  .text\n"
@@ -83,6 +145,7 @@ __asm__ (
     "  bnez    a6, 3b\n"
     "  j      .Lfixup_stack_ret");
 #endif
+#endif /* __FDPIC__ */
 
 /* Get a pointer to the argv value.  */
 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
@@ -90,7 +153,7 @@ __asm__ (
 /* Function calls are not safe until the GOT relocations have been done.  */
 #define NO_FUNCS_BEFORE_BOOTSTRAP
 
-#if defined(__ARCH_USE_MMU__)
+#if defined(__ARCH_USE_MMU__) && !defined(__FDPIC__)
 #define PERFORM_BOOTSTRAP_GOT(tpnt) \
 do { \
        xtensa_got_location *got_loc; \
@@ -128,3 +191,29 @@ do { \
        } \
 } while (0)
 #endif
+
+#ifdef __FDPIC__
+#undef DL_START
+#define DL_START(X)   \
+static void  __attribute__ ((used)) \
+_dl_start (Elf32_Addr dl_boot_got_pointer, \
+          struct elf32_fdpic_loadmap *dl_boot_progmap, \
+          struct elf32_fdpic_loadmap *dl_boot_ldsomap, \
+          Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
+          struct funcdesc_value *dl_main_funcdesc, \
+          X)
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  We return the address of the function's entry point to
+ * _dl_boot, see boot1_arch.h.
+ */
+#define START()        do {                                                    
\
+  struct elf_resolve *exec_mod = _dl_loaded_modules;                   \
+  dl_main_funcdesc->entry_point = _dl_elf_main;                                
\
+  while (exec_mod->libtype != elf_executable)                          \
+    exec_mod = exec_mod->next;                                         \
+  dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value;          \
+  return;                                                              \
+} while (0)
+#endif /* __FDPIC__ */
diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h
index 6b908989a8f1..5aa3e177f3a1 100644
--- a/ldso/ldso/xtensa/dl-sysdep.h
+++ b/ldso/ldso/xtensa/dl-sysdep.h
@@ -26,6 +26,7 @@
    in l_info array.  */
 #define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM)
 
+#ifndef __FDPIC__
 typedef struct xtensa_got_location_struct {
   Elf32_Off offset;
   Elf32_Word length;
@@ -86,6 +87,7 @@ typedef struct xtensa_got_location_struct {
     else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ)                      \
       dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val;              \
   } while (0)
+#endif
 
 /* Here we define the magic numbers that this dynamic loader should accept. */
 #define MAGIC1 EM_XTENSA
@@ -115,10 +117,41 @@ elf_machine_dynamic (void)
   return (Elf32_Addr) &_DYNAMIC;
 }
 
+#ifdef __FDPIC__
+
+#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \
+do \
+{ \
+  (piclib) = 2; \
+} \
+while (0)
+
+/* We must force strings used early in the bootstrap into the data
+   segment.  */
+#undef SEND_EARLY_STDERR
+#define SEND_EARLY_STDERR(S) \
+  do { /* FIXME: implement */; } while (0)
+
+#undef INIT_GOT
+#include "../fdpic/dl-sysdep.h"
+#undef INIT_GOT
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+  (MODULE)->loadaddr.got_value = (GOT_BASE); \
+  GOT_BASE[0] = ((unsigned long *)&_dl_linux_resolve)[0]; \
+  GOT_BASE[1] = ((unsigned long *)&_dl_linux_resolve)[1]; \
+  GOT_BASE[2] = (unsigned long) MODULE; \
+}
+
+#endif /* __FDPIC__ */
+
 /* Return the run-time load address of the shared object.  */
 static __always_inline Elf32_Addr
 elf_machine_load_address (void)
 {
+#ifdef __FDPIC__
+  return 0;
+#else
   Elf32_Addr addr, tmp;
 
   /* At this point, the runtime linker is being bootstrapped and the GOT
@@ -135,11 +168,41 @@ elf_machine_load_address (void)
           : "=a" (addr), "=a" (tmp));
 
   return addr - 3;
+#endif
 }
 
+#ifdef __FDPIC__
+
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB)   \
+       switch (ELF_R_TYPE((RELP)->r_info)){                    \
+       case R_XTENSA_SYM32:                                    \
+               *(REL)  = (SYMBOL) + (RELP)->r_addend;          \
+               break;                                          \
+       case R_XTENSA_RELATIVE:                                 \
+       case R_XTENSA_NONE:                                     \
+       default:                                                \
+               break;                                          \
+       }
+
 static __always_inline void
-elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr,
                      Elf32_Word relative_count)
+{
+  Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
+  while (relative_count--)
+    {
+      Elf32_Addr *const reloc_addr = (Elf32_Addr *) DL_RELOC_ADDR(load_off, 
rpnt->r_offset);
+      *reloc_addr = DL_RELOC_ADDR(load_off, *reloc_addr);
+      rpnt++;
+    }
+}
+#else
+static __always_inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+                     Elf32_Word relative_count)
 {
   Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
   while (relative_count--)
@@ -149,3 +212,4 @@ elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr 
rel_addr,
       rpnt++;
     }
 }
+#endif
diff --git a/ldso/ldso/xtensa/dl-tlsdesc.S b/ldso/ldso/xtensa/dl-tlsdesc.S
index 426f2180b3c0..1a8eacff20cc 100644
--- a/ldso/ldso/xtensa/dl-tlsdesc.S
+++ b/ldso/ldso/xtensa/dl-tlsdesc.S
@@ -24,6 +24,9 @@
 
        .text
 HIDDEN_ENTRY (_dl_tlsdesc_return)
+#ifdef __FDPIC__
+       l32i            a2, a2, 4
+#endif
        rur.threadptr   a3
        add             a2, a2, a3
        abi_ret
@@ -53,7 +56,9 @@ END (_dl_tlsdesc_return)
         */
 
 HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
-
+#ifdef __FDPIC__
+       l32i    a2, a2, 4
+#endif
        /* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
        rur.threadptr   a3
        l32i    a4, a3, 0
@@ -86,7 +91,8 @@ HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
 #elif defined(__XTENSA_CALL0_ABI__)
        addi    a1, a1, -16
        s32i    a0, a1, 0
-       movi    a0, __tls_get_addr
+       movi    a0, JUMPTARGET(__tls_get_addr)
+       FDPIC_LOAD_JUMPTARGET(a0, a11, a0)
        callx0  a0
        l32i    a0, a1, 0
        addi    a1, a1, 16
diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c
index e38a02666477..d97f234353e8 100644
--- a/ldso/ldso/xtensa/elfinterp.c
+++ b/ldso/ldso/xtensa/elfinterp.c
@@ -36,6 +36,13 @@
 #include "tlsdeschtab.h"
 #endif
 
+#ifdef __FDPIC__
+unsigned long
+_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
+{
+       return 0;
+}
+#else
 unsigned long
 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 {
@@ -83,7 +90,7 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 
        return (unsigned long) new_addr;
 }
-
+#endif
 
 static int
 _dl_parse (struct elf_resolve *tpnt, struct r_scope_elem *scope,
@@ -145,8 +152,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem 
*scope,
        int reloc_type;
        int symtab_index;
        char *symname;
-#if defined USE_TLS && USE_TLS
-       struct elf_resolve *tls_tpnt = NULL;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+       struct elf_resolve *def_mod = NULL;
 #endif
        struct symbol_ref sym_ref;
        ElfW(Addr) *reloc_addr;
@@ -155,7 +162,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem 
*scope,
        ElfW(Addr) old_val;
 #endif
 
-       reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset);
+       reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, 
rpnt->r_offset);
        reloc_type = ELF_R_TYPE (rpnt->r_info);
        symtab_index = ELF_R_SYM (rpnt->r_info);
        sym_ref.sym = &symtab[symtab_index];
@@ -164,9 +171,17 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
        symname = strtab + sym_ref.sym->st_name;
 
        if (symtab_index) {
-               symbol_addr = (ElfW(Addr))
-                       _dl_find_hash (symname, scope, tpnt,
-                                                  elf_machine_type_class 
(reloc_type), &sym_ref);
+               if (ELF_ST_BIND (sym_ref.sym->st_info) == STB_LOCAL) {
+                       symbol_addr = (ElfW(Addr))
+                               DL_RELOC_ADDR(tpnt->loadaddr,
+                                             symtab[symtab_index].st_value);
+                       sym_ref.tpnt = tpnt;
+               } else {
+                       symbol_addr = (ElfW(Addr))
+                               _dl_find_hash (symname, scope, tpnt,
+                                              elf_machine_type_class 
(reloc_type),
+                                              &sym_ref);
+               }
 
                /*
                 * We want to allow undefined references to weak symbols - this 
might
@@ -182,13 +197,13 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
                        _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
                                                &sym_ref, 
elf_machine_type_class(reloc_type));
                }
-#if defined USE_TLS && USE_TLS
-               tls_tpnt = sym_ref.tpnt;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+               def_mod = sym_ref.tpnt;
 #endif
        } else {
                symbol_addr =symtab[symtab_index].st_value;
-#if defined USE_TLS && USE_TLS
-               tls_tpnt = tpnt;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+               def_mod = tpnt;
 #endif
        }
 
@@ -202,6 +217,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem 
*scope,
 
        case R_XTENSA_GLOB_DAT:
        case R_XTENSA_JMP_SLOT:
+       case R_XTENSA_SYM32:
                *reloc_addr = symbol_addr + rpnt->r_addend;
                break;
 
@@ -219,19 +235,63 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
                break;
 
        case R_XTENSA_RELATIVE:
-               *reloc_addr += tpnt->loadaddr + rpnt->r_addend;
+               *reloc_addr += DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_addend);
                break;
 
+#ifdef __FDPIC__
+       case R_XTENSA_FUNCDESC_VALUE:
+               {
+                       struct funcdesc_value *dst = (struct funcdesc_value *) 
reloc_addr;
+
+                       dst->entry_point = (void *) (symbol_addr + 
rpnt->r_addend);
+                       dst->got_value = def_mod->loadaddr.got_value;
+               }
+               break;
+       case R_XTENSA_FUNCDESC:
+               if (symbol_addr)
+                       *reloc_addr = (unsigned long)
+                               _dl_funcdesc_for((void *) (symbol_addr + 
rpnt->r_addend),
+                                                
sym_ref.tpnt->loadaddr.got_value);
+               else
+                       /* Relocation against an undefined weak symbol:
+                          set funcdesc to zero.  */
+                       *reloc_addr = 0;
+               break;
+       case R_XTENSA_TLS_TPOFF:
+               CHECK_STATIC_TLS((struct link_map *) def_mod);
+               *reloc_addr = symbol_addr + rpnt->r_addend + 
def_mod->l_tls_offset;
+               break;
+       case R_XTENSA_TLSDESC:
+               {
+                       struct tlsdesc *td = (struct tlsdesc *) reloc_addr;
+#ifndef SHARED
+                       CHECK_STATIC_TLS((struct link_map *) def_mod);
+#else
+                       if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
+                       {
+                               td->entry = _dl_tlsdesc_dynamic;
+                               td->argument = _dl_make_tlsdesc_dynamic((struct 
link_map *) def_mod,
+                                                                       
symbol_addr + rpnt->r_addend);
+                       }
+                       else
+#endif
+                       {
+                               td->entry = _dl_tlsdesc_return;
+                               td->argument = (void *) (symbol_addr + 
rpnt->r_addend + def_mod->l_tls_offset);
+                       }
+               }
+               break;
+#else
 #if defined USE_TLS && USE_TLS
        case R_XTENSA_TLS_TPOFF:
-               CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
-               *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + 
rpnt->r_addend;
+               CHECK_STATIC_TLS((struct link_map *) def_mod);
+               *reloc_addr = symbol_addr + rpnt->r_addend + 
def_mod->l_tls_offset;
                break;
        case R_XTENSA_TLSDESC_FN:
 #ifndef SHARED
-               CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+               CHECK_STATIC_TLS((struct link_map *) def_mod);
 #else
-               if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+               if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
                        *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic;
                else
 #endif
@@ -239,25 +299,25 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
                break;
        case R_XTENSA_TLSDESC_ARG:
 #ifndef SHARED
-               CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+               CHECK_STATIC_TLS((struct link_map *) def_mod);
 #else
-               if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+               if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
                        *reloc_addr = (ElfW(Addr))
-                               _dl_make_tlsdesc_dynamic((struct link_map *) 
tls_tpnt,
+                               _dl_make_tlsdesc_dynamic((struct link_map *) 
def_mod,
                                                         symbol_addr + 
rpnt->r_addend);
                else
 #endif
                        *reloc_addr = symbol_addr + rpnt->r_addend +
-                               tls_tpnt->l_tls_offset;
+                               def_mod->l_tls_offset;
                break;
 #endif
-
+#endif
        default:
                return -1; /* Calls _dl_exit(1).  */
        }
 #if defined (__SUPPORT_LD_DEBUG__)
        if (_dl_debug_reloc && _dl_debug_detail)
-               _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
+               _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n",
                                         old_val, *reloc_addr, reloc_addr);
 #endif
 
@@ -275,7 +335,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
        ElfW(Addr) old_val;
 #endif
 
-       reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset);
+       reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, 
rpnt->r_offset);
        reloc_type = ELF_R_TYPE (rpnt->r_info);
 
 #if defined (__SUPPORT_LD_DEBUG__)
@@ -286,7 +346,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
        case R_XTENSA_JMP_SLOT:
                /* Perform a RELATIVE reloc on the GOT entry that transfers
                   to the stub function.  */
-               *reloc_addr += tpnt->loadaddr;
+               *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, *reloc_addr);
                break;
        case R_XTENSA_NONE:
                break;
@@ -296,7 +356,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
 
 #if defined (__SUPPORT_LD_DEBUG__)
        if (_dl_debug_reloc && _dl_debug_detail)
-               _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
+               _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n",
                                         old_val, *reloc_addr, reloc_addr);
 #endif
        return 0;
@@ -320,3 +380,7 @@ _dl_parse_relocation_information (struct dyn_elf *rpnt,
        return _dl_parse (rpnt->dyn, scope, rel_addr, rel_size,
                                          _dl_do_reloc);
 }
+
+#ifndef IS_IN_libdl
+# include "../../libc/sysdeps/linux/xtensa/crtreloc.c"
+#endif
diff --git a/libc/sysdeps/linux/xtensa/__start_context.S 
b/libc/sysdeps/linux/xtensa/__start_context.S
index a30d7b6188ad..e6ce93347d6d 100644
--- a/libc/sysdeps/linux/xtensa/__start_context.S
+++ b/libc/sysdeps/linux/xtensa/__start_context.S
@@ -22,9 +22,10 @@
  * There's no entry instruction, makecontext sets up ucontext_t as if
  * getcontext was called above and is about to return here.
  * Registers on entry to this function:
- *   a12: func to call
+ *   a12: func to call (function descriptor in case of FDPIC)
  *   a13: ucp->uc_link, next context to activate if func returns
  *   a14: func argc
+ *   a15: current GOT pointer (in case of FDPIC)
  */
        .literal_position
 
@@ -46,14 +47,17 @@ ENTRY_PREFIX(__start_context)
        addi    a1, a1, 16
        /* func arguments 6..argc - 1 are now at the top of the stack */
 1:
+       FDPIC_LOAD_FUNCDESC (a12, a12)
        callx0  a12
        beqz    a13, 1f
        mov     a2, a13
        movi    a4, JUMPTARGET (setcontext)
+       FDPIC_LOAD_JUMPTARGET (a4, a15, a4)
        callx0  a4
 1:
        movi    a4, JUMPTARGET (_exit)
        movi    a2, 0
+       FDPIC_LOAD_JUMPTARGET (a4, a15, a4)
        callx0  a4
        ill
 END(__start_context)
diff --git a/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h 
b/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h
new file mode 100644
index 000000000000..19bb247b878e
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h
@@ -0,0 +1,117 @@
+/* Copyright 2003, 2004 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file.  (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_ELF_FDPIC_H
+#define _BITS_ELF_FDPIC_H
+
+/* These data structures are described in the FDPIC ABI extension.
+   The kernel passes a process a memory map, such that for every LOAD
+   segment there is an elf32_fdpic_loadseg entry.  A pointer to an
+   elf32_fdpic_loadmap is passed in r7 at start-up, and a pointer to
+   an additional such map is passed in r8 for the interpreter, when
+   there is one.  */
+
+#include <elf.h>
+
+/* This data structure represents a PT_LOAD segment.  */
+struct elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  Elf32_Word p_memsz;
+};
+
+struct elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  Elf32_Half version;
+  /* Number of segments in this map.  */
+  Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
+struct elf32_fdpic_loadaddr {
+  struct elf32_fdpic_loadmap *map;
+  void *got_value;
+};
+
+/* Map a pointer's VMA to its corresponding address according to the
+   load map.  */
+static __always_inline void *
+__reloc_pointer (void *p,
+                const struct elf32_fdpic_loadmap *map)
+{
+  int c;
+
+#if 0
+  if (map->version != 0)
+    /* Crash.  */
+    ((void(*)())0)();
+#endif
+
+  /* No special provision is made for NULL.  We don't want NULL
+     addresses to go through relocation, so they shouldn't be in
+     .rofixup sections, and, if they're present in dynamic
+     relocations, they shall be mapped to the NULL address without
+     undergoing relocations.  */
+
+  for (c = 0;
+       /* Take advantage of the fact that the loadmap is ordered by
+         virtual addresses.  In general there will only be 2 entries,
+         so it's not profitable to do a binary search.  */
+       c < map->nsegs && p >= (void*)map->segs[c].p_vaddr;
+       c++)
+    {
+      /* This should be computed as part of the pointer comparison
+        above, but we want to use the carry in the comparison, so we
+        can't convert it to an integer type beforehand.  */
+      unsigned long offset = (char*)p - (char*)map->segs[c].p_vaddr;
+      /* We only check for one-past-the-end for the last segment,
+        assumed to be the data segment, because other cases are
+        ambiguous in the absence of padding between segments, and
+        rofixup already serves as padding between text and data.
+        Unfortunately, unless we special-case the last segment, we
+        fail to relocate the _end symbol.  */
+      if (offset < map->segs[c].p_memsz
+         || (offset == map->segs[c].p_memsz && c + 1 == map->nsegs))
+       return (char*)map->segs[c].addr + offset;
+    }
+
+  /* We might want to crash instead.  */
+  return (void*)-1;
+}
+
+# define __RELOC_POINTER(ptr, loadaddr) \
+  (__reloc_pointer ((void*)(ptr), \
+                   (loadaddr).map))
+
+void*
+__self_reloc (const struct elf32_fdpic_loadmap *map, void ***p, void ***e);
+
+#endif /* _BITS_ELF_FDPIC_H */
diff --git a/libc/sysdeps/linux/xtensa/clone.S 
b/libc/sysdeps/linux/xtensa/clone.S
index ebfdcc1f65be..a11044cd0271 100644
--- a/libc/sysdeps/linux/xtensa/clone.S
+++ b/libc/sysdeps/linux/xtensa/clone.S
@@ -81,11 +81,17 @@ ENTRY (__clone)
        callx4  a2
 #elif defined(__XTENSA_CALL0_ABI__)
        mov     a2, a9                  /* load up the 'arg' parameter */
+#ifdef __FDPIC__
+       mov     a12, a11
+       l32i    a11, a7, 4
+       l32i    a7, a7, 0
+#endif
        callx0  a7                      /* call the user's function */
 
        /* Call _exit.  Note that any return parameter from the user's
           function in a2 is seen as inputs to _exit.  */
        movi    a0, JUMPTARGET(_exit)
+       FDPIC_LOAD_JUMPTARGET(a0, a12, a0)
        callx0  a0
 #else
 #error Unsupported Xtensa ABI
diff --git a/libc/sysdeps/linux/xtensa/crt1.S b/libc/sysdeps/linux/xtensa/crt1.S
index 3fa14ae583a9..a12f82dd656b 100644
--- a/libc/sysdeps/linux/xtensa/crt1.S
+++ b/libc/sysdeps/linux/xtensa/crt1.S
@@ -35,6 +35,86 @@
 
 #include <features.h>
 
+#if defined(__FDPIC__)
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.  When the entry point runs, most register values are unspecified,
+   except for:
+
+       a6      Address of .dynamic section
+       a5      Interpreter map
+       a4      Executable map
+
+       a2      Contains a function pointer to be registered with `atexit'.
+               This is how the dynamic linker arranges to have DT_FINI
+               functions called for shared libraries that have been loaded
+               before this code runs.
+
+       a1      The stack (i.e., a1+16) contains the arguments and environment:
+               a1+0                    argc
+               a1+4                    argv[0]
+               ...
+               a1+(4*argc)             NULL
+               a1+(4*(argc+1))         envp[0]
+               ...
+                                       NULL
+ */
+       .text
+       .align  4
+       .literal_position
+       .global _start
+       .type   _start, @function
+_start:
+#if defined(__XTENSA_CALL0_ABI__)
+
+       .begin  no-transform
+       call0   1f
+2:
+       .end    no-transform
+       .align  4
+       .literal_position
+1:
+       movi    a15, 2b
+       sub     a15, a0, a15
+
+       mov     a12, a4
+       mov     a13, a5
+       mov     a14, a6
+       mov     a2, a4
+       movi    a3, __ROFIXUP_LIST__
+       add     a3, a3, a15
+       movi    a4, __ROFIXUP_END__
+       add     a4, a4, a15
+       movi    a0, __self_reloc
+       add     a0, a0, a15
+       callx0  a0
+
+       mov     a11, a2
+       movi    a2, main@GOTOFFFUNCDESC
+       add     a2, a2, a11
+       l32i    a3, sp, 0       /* argc */
+       addi    a4, sp, 4       /* argv */
+       /* a5 is either 0 when static or set by the RTLD to the rtld_fini */
+       mov     a7, a13
+       /* unused stack_end argument is what used to be argc */
+       movi    a5, _init@GOTOFFFUNCDESC
+       add     a5, a5, a11
+       movi    a6, _fini@GOTOFFFUNCDESC
+       add     a6, a6, a11
+
+       movi    a0, __uClibc_main@GOTOFFFUNCDESC
+       add     a0, a0, a11
+       l32i    a11, a0, 4
+       l32i    a0, a0, 0
+       callx0  a0
+       ill
+
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+#else /* defined(__FDPIC__) */
+
 #ifndef __UCLIBC_CTOR_DTOR__
         .weak _init
         .weak _fini
@@ -173,3 +253,4 @@ __data_start:
        .long   0
        .weak   data_start
        data_start = __data_start
+#endif /* defined(__FDPIC__) */
diff --git a/libc/sysdeps/linux/xtensa/crti.S b/libc/sysdeps/linux/xtensa/crti.S
index 43e66e30820b..2923ff09d0bb 100644
--- a/libc/sysdeps/linux/xtensa/crti.S
+++ b/libc/sysdeps/linux/xtensa/crti.S
@@ -11,6 +11,10 @@ _init:
 #elif defined(__XTENSA_CALL0_ABI__)
        addi    sp, sp, -16
        s32i    a0, sp, 0
+#ifdef __FDPIC__
+       s32i    a12, sp, 4
+       mov     a12, a11
+#endif
 #else
 #error Unsupported Xtensa ABI
 #endif
@@ -26,6 +30,10 @@ _fini:
 #elif defined(__XTENSA_CALL0_ABI__)
        addi    sp, sp, -16
        s32i    a0, sp, 0
+#ifdef __FDPIC__
+       s32i    a12, sp, 4
+       mov     a12, a11
+#endif
 #else
 #error Unsupported Xtensa ABI
 #endif
diff --git a/libc/sysdeps/linux/xtensa/crtn.S b/libc/sysdeps/linux/xtensa/crtn.S
index a3598da1a537..6f797e8bdd60 100644
--- a/libc/sysdeps/linux/xtensa/crtn.S
+++ b/libc/sysdeps/linux/xtensa/crtn.S
@@ -4,6 +4,9 @@
 #if defined(__XTENSA_WINDOWED_ABI__)
        retw
 #elif defined(__XTENSA_CALL0_ABI__)
+#ifdef __FDPIC__
+       l32i    a12, sp, 4
+#endif
        l32i    a0, sp, 0
        addi    sp, sp, 16
        ret
@@ -15,6 +18,9 @@
 #if defined(__XTENSA_WINDOWED_ABI__)
        retw
 #elif defined(__XTENSA_CALL0_ABI__)
+#ifdef __FDPIC__
+       l32i    a12, sp, 4
+#endif
        l32i    a0, sp, 0
        addi    sp, sp, 16
        ret
diff --git a/libc/sysdeps/linux/xtensa/crtreloc.c 
b/libc/sysdeps/linux/xtensa/crtreloc.c
new file mode 100644
index 000000000000..697ef91ab21f
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/crtreloc.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   written by Alexandre Oliva <aol...@redhat.com>
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file.  (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef __FDPIC__
+
+#include <sys/types.h>
+#include <link.h>
+
+/* This file is to be compiled into crt object files, to enable
+   executables to easily self-relocate.  */
+
+/* Compute the runtime address of pointer in the range [p,e), and then
+   map the pointer pointed by it.  */
+static __always_inline void ***
+reloc_range_indirect (void ***p, void ***e,
+                     const struct elf32_fdpic_loadmap *map)
+{
+  while (p < e)
+    {
+      if (*p != (void **)-1)
+       {
+         void *ptr = __reloc_pointer (*p, map);
+
+         if (ptr != (void *)-1)
+           {
+             unsigned long off = ((unsigned long)ptr & 3) * 8;
+             unsigned long *pa = (unsigned long *)((unsigned long)ptr & -4);
+             unsigned long v2;
+             void *pt;
+
+             if (off)
+               {
+                 unsigned long v0, v1;
+#ifdef __XTENSA_EB__
+                 v0 = pa[1]; v1 = pa[0];
+                 v2 = (v1 >> (32 - off)) | (v0 << off);
+#else /* __XTENSA_EL__ */
+                 v0 = pa[0]; v1 = pa[1];
+                 v2 = (v0 << (32 - off)) | (v1 >> off);
+#endif
+                 pt = (void *)((v1 << (32 - off)) | (v0 >> off));
+               }
+             else
+               pt = *(void**)ptr;
+             pt = __reloc_pointer (pt, map);
+             if (off)
+               {
+                 unsigned long v = (unsigned long)pt;
+#ifdef __XTENSA_EB__
+                 pa[0] = (v2 << (32 - off)) | (v >> off);
+                 pa[1] = (v << (32 - off)) | (v2 >> off);
+#else /* __XTENSA_EL__ */
+                 pa[0] = (v2 >> (32 - off)) | (v << off);
+                 pa[1] = (v >> (32 - off)) | (v2 << off);
+#endif
+               }
+             else
+               *(void**)ptr = pt;
+           }
+       }
+      p++;
+    }
+  return p;
+}
+
+/* Call __reloc_range_indirect for the given range except for the last
+   entry, whose contents are only relocated.  It's expected to hold
+   the GOT value.  */
+attribute_hidden void*
+__self_reloc (const struct elf32_fdpic_loadmap *map,
+             void ***p, void ***e)
+{
+  p = reloc_range_indirect (p, e-1, map);
+
+  if (p >= e)
+    return (void*)-1;
+
+  return __reloc_pointer (*p, map);
+}
+
+#endif /* __FDPIC__ */
diff --git a/libc/sysdeps/linux/xtensa/getcontext.S 
b/libc/sysdeps/linux/xtensa/getcontext.S
index 7588a91b33b3..4cc644552d42 100644
--- a/libc/sysdeps/linux/xtensa/getcontext.S
+++ b/libc/sysdeps/linux/xtensa/getcontext.S
@@ -33,6 +33,7 @@ ENTRY(__getcontext)
        addi    a4, a2, UCONTEXT_SIGMASK
        movi    a2, SIG_BLOCK
        movi    a5, JUMPTARGET (sigprocmask)
+       FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
        jx      a5
 END(__getcontext)
 #elif defined(__XTENSA_WINDOWED_ABI__)
diff --git a/libc/sysdeps/linux/xtensa/makecontext.c 
b/libc/sysdeps/linux/xtensa/makecontext.c
index da26a0130325..0a8f7116fef2 100644
--- a/libc/sysdeps/linux/xtensa/makecontext.c
+++ b/libc/sysdeps/linux/xtensa/makecontext.c
@@ -73,7 +73,12 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int 
argc, ...)
     sp -= 4 * (argc + 2);
   sp &= -16;
 
+#ifdef __FDPIC__
+  ucp->uc_mcontext.sc_pc = ((unsigned long *) __start_context)[0];
+  ucp->uc_mcontext.sc_a[15] = ((unsigned long *) __start_context)[1];
+#else
   ucp->uc_mcontext.sc_pc = (unsigned long) __start_context;
+#endif
   ucp->uc_mcontext.sc_a[1] = sp;
   ucp->uc_mcontext.sc_a[12] = (unsigned long) func;
   ucp->uc_mcontext.sc_a[13] = (unsigned long) ucp->uc_link;
diff --git a/libc/sysdeps/linux/xtensa/setcontext.S 
b/libc/sysdeps/linux/xtensa/setcontext.S
index 4df7cc049006..72915ef8d74e 100644
--- a/libc/sysdeps/linux/xtensa/setcontext.S
+++ b/libc/sysdeps/linux/xtensa/setcontext.S
@@ -28,6 +28,7 @@ ENTRY(__setcontext)
        movi    a4, 0
        movi    a2, SIG_SETMASK
        movi    a5, JUMPTARGET (sigprocmask)
+       FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
        callx0  a5
        bnez    a2, .Lerror
 
diff --git a/libc/sysdeps/linux/xtensa/setjmp.S 
b/libc/sysdeps/linux/xtensa/setjmp.S
index b8152fdd8bac..d629c11a8c41 100644
--- a/libc/sysdeps/linux/xtensa/setjmp.S
+++ b/libc/sysdeps/linux/xtensa/setjmp.S
@@ -155,7 +155,8 @@ ENTRY (__sigsetjmp)
        s32i    a14, a2, 16
        s32i    a15, a2, 20
        mov     a12, a2
-       movi    a0, __sigjmp_save
+       movi    a0, JUMPTARGET(__sigjmp_save)
+       FDPIC_LOAD_JUMPTARGET(a0, a11, a0)
        callx0  a0
        l32i    a0, a12, 0
        l32i    a12, a12, 8
diff --git a/libc/sysdeps/linux/xtensa/swapcontext.S 
b/libc/sysdeps/linux/xtensa/swapcontext.S
index a215edc6d54a..40b38e98ca01 100644
--- a/libc/sysdeps/linux/xtensa/swapcontext.S
+++ b/libc/sysdeps/linux/xtensa/swapcontext.S
@@ -36,6 +36,7 @@ ENTRY(__swapcontext)
        addi    a4, a2, UCONTEXT_SIGMASK
        movi    a2, SIG_SETMASK
        movi    a5, JUMPTARGET (sigprocmask)
+       FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
        callx0  a5
        bnez    a2, .Lerror
 
diff --git a/libc/sysdeps/linux/xtensa/sysdep.h 
b/libc/sysdeps/linux/xtensa/sysdep.h
index 80b3f30fcc5d..d05741027c07 100644
--- a/libc/sysdeps/linux/xtensa/sysdep.h
+++ b/libc/sysdeps/linux/xtensa/sysdep.h
@@ -75,13 +75,27 @@
 #define LITERAL_POSITION .literal_position
 
 #undef JUMPTARGET
-#ifdef __PIC__
+#if defined(__FDPIC__)
+#define JUMPTARGET(name) name##@GOTOFFFUNCDESC
+#define FDPIC_LOAD_FUNCDESC(call_target, funcdesc)             \
+       l32i    a11, funcdesc, 4;                               \
+       l32i    call_target, funcdesc, 0
+
+#define FDPIC_LOAD_JUMPTARGET(call_target, got_base, jumptarget)\
+       add     call_target, got_base, jumptarget;              \
+       FDPIC_LOAD_FUNCDESC(call_target, call_target)
+
+#elif defined(__PIC__)
 /* The "@PLT" suffix is currently a no-op for non-shared linking, but
    it doesn't hurt to use it conditionally for PIC code in case that
    changes someday.  */
 #define JUMPTARGET(name) name##@PLT
+#define FDPIC_LOAD_FUNCDESC(call_target, funcdesc)
+#define FDPIC_LOAD_JUMPTARGET(call_target, got_base, jumptarget)
 #else
 #define JUMPTARGET(name) name
+#define FDPIC_LOAD_FUNCDESC(call_target, funcdesc)
+#define FDPIC_LOAD_JUMPTARGET(call_target, got_base, jumptarget)
 #endif
 
 #ifndef FRAMESIZE
@@ -153,6 +167,21 @@
 
 #if defined _LIBC_REENTRANT
 # if defined USE___THREAD
+#ifdef __FDPIC__
+#   define SYSCALL_ERROR_ERRNO errno
+#  define SYSCALL_ERROR_HANDLER                                                
      \
+0:     rur     a4, THREADPTR;                                                \
+       movi    a3, SYSCALL_ERROR_ERRNO@GOTTPOFF;                             \
+       .reloc  ., R_XTENSA_TLS_TPOFF_PTR, SYSCALL_ERROR_ERRNO;               \
+       add     a3, a3, a11;                                                  \
+       .reloc  ., R_XTENSA_TLS_TPOFF_LOAD, SYSCALL_ERROR_ERRNO;              \
+       l32i    a3, a3, 0;                                                    \
+       neg     a2, a2;                                                       \
+       add     a4, a4, a3;                                                   \
+       s32i    a2, a4, 0;                                                    \
+       movi    a2, -1;                                                       \
+       j       .Lpseudo_end;
+#else
 #   define SYSCALL_ERROR_ERRNO errno
 #  define SYSCALL_ERROR_HANDLER                                                
      \
 0:     rur     a4, THREADPTR;                                                \
@@ -162,13 +191,14 @@
        s32i    a2, a4, 0;                                                    \
        movi    a2, -1;                                                       \
        j       .Lpseudo_end;
+#endif
 # else /* !USE___THREAD */
 
 #if defined(__XTENSA_WINDOWED_ABI__)
 #  define SYSCALL_ERROR_HANDLER                                                
      \
 0:     neg     a2, a2;                                                       \
        mov     a6, a2;                                                       \
-       movi    a4, __errno_location@PLT;                                     \
+       movi    a4, JUMPTARGET(__errno_location);                             \
        callx4  a4;                                                           \
        s32i    a2, a6, 0;                                                    \
        movi    a2, -1;                                                       \
@@ -179,7 +209,8 @@
        addi    a1, a1, -16;                                                  \
        s32i    a0, a1, 0;                                                    \
        s32i    a2, a1, 4;                                                    \
-       movi    a0, __errno_location@PLT;                                     \
+       movi    a0, JUMPTARGET(__errno_location);                             \
+       FDPIC_LOAD_JUMPTARGET(a0, a11, a0);                                   \
        callx0  a0;                                                           \
        l32i    a0, a1, 0;                                                    \
        l32i    a3, a1, 4;                                                    \
@@ -193,12 +224,23 @@
 
 # endif /* !USE___THREAD */
 #else /* !_LIBC_REENTRANT */
+#ifdef __FDPIC__
+#define SYSCALL_ERROR_HANDLER                                                \
+0:     movi    a4, errno@GOT;                                                \
+       add     a4, a4, a11;                                                  \
+       l32i    a4, a4, 0;                                                    \
+       neg     a2, a2;                                                       \
+       s32i    a2, a4, 0;                                                    \
+       movi    a2, -1;                                                       \
+       j       .Lpseudo_end;
+#else
 #define SYSCALL_ERROR_HANDLER                                                \
 0:     movi    a4, errno;                                                    \
        neg     a2, a2;                                                       \
        s32i    a2, a4, 0;                                                    \
        movi    a2, -1;                                                       \
        j       .Lpseudo_end;
+#endif /* __FDPIC__ */
 #endif /* _LIBC_REENTRANT */
 
 #endif /* __ASSEMBLER__ */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch 
b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch
index 6f17348713ad..a3719a3fb3af 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch
@@ -9,3 +9,5 @@ CFLAGS-OMIT-fork.c = -DNOT_IN_libc -DIS_IN_libpthread
 
 ASFLAGS-syscall.S = -D_LIBC_REENTRANT
 ASFLAGS-mmap.S = -D_LIBC_REENTRANT
+
+ASFLAGS += -DUSE___THREAD
diff --git a/libpthread/nptl/sysdeps/xtensa/dl-tls.h 
b/libpthread/nptl/sysdeps/xtensa/dl-tls.h
index adc02d74a55c..5fc4ea2d05c8 100644
--- a/libpthread/nptl/sysdeps/xtensa/dl-tls.h
+++ b/libpthread/nptl/sysdeps/xtensa/dl-tls.h
@@ -28,6 +28,29 @@ typedef struct
 
 extern void *__tls_get_addr (tls_index *ti);
 
+/* Type used as the argument in a TLS descriptor for a symbol that
+   needs dynamic TLS offsets.  */
+struct tlsdesc_dynamic_arg
+{
+  tls_index tlsinfo;
+  size_t gen_count;
+};
+
+#ifdef __FDPIC__
+/* Type used to represent a TLS descriptor.  */
+struct tlsdesc
+{
+  ptrdiff_t (*entry)(struct tlsdesc *);
+  void *argument;
+};
+
+extern ptrdiff_t attribute_hidden
+  _dl_tlsdesc_return(struct tlsdesc *);
+
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
+extern ptrdiff_t attribute_hidden
+  _dl_tlsdesc_dynamic(struct tlsdesc *);
+#else
 /* Type used to represent a TLS descriptor.  */
 struct tlsdesc
 {
@@ -39,19 +62,11 @@ struct tlsdesc
   ptrdiff_t (*entry)(struct tlsdesc *);
 };
 
-/* Type used as the argument in a TLS descriptor for a symbol that
-   needs dynamic TLS offsets.  */
-struct tlsdesc_dynamic_arg
-{
-  tls_index tlsinfo;
-  size_t gen_count;
-};
-
 extern ptrdiff_t attribute_hidden
   _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *);
 
 extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
 extern ptrdiff_t attribute_hidden
   _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *);
-
+#endif
 #endif
-- 
2.39.2

_______________________________________________
devel mailing list -- devel@uclibc-ng.org
To unsubscribe send an email to devel-le...@uclibc-ng.org

Reply via email to