Browse Source

xtensa: add FDPIC support

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 <jcmvbkbc@gmail.com>
Max Filippov 1 year ago
parent
commit
138274e92a

+ 4 - 0
Rules.mak

@@ -520,6 +520,10 @@ ifeq ($(TARGET_ARCH),c6x)
 	CPU_LDFLAGS-y += $(CPU_CFLAGS)
 	CPU_LDFLAGS-y += $(CPU_CFLAGS)
 endif
 endif
 
 
+ifeq ($(TARGET_ARCH),xtensa)
+	CPU_CFLAGS-$(UCLIBC_FORMAT_FDPIC_ELF) += -mfdpic
+endif
+
 $(eval $(call check-gcc-var,$(PIEFLAG_NAME)))
 $(eval $(call check-gcc-var,$(PIEFLAG_NAME)))
 PIEFLAG := $(CFLAG_$(PIEFLAG_NAME))
 PIEFLAG := $(CFLAG_$(PIEFLAG_NAME))
 ifeq ($(PIEFLAG),)
 ifeq ($(PIEFLAG),)

+ 1 - 1
extra/Configs/Config.in

@@ -615,7 +615,7 @@ config UCLIBC_HAS_THREADS_NATIVE
 		   !TARGET_h8300 && \
 		   !TARGET_h8300 && \
 		   !TARGET_hppa && \
 		   !TARGET_hppa && \
 		   !TARGET_ia64 && \
 		   !TARGET_ia64 && \
-		   (ARCH_USE_MMU || TARGET_arm)
+		   (ARCH_USE_MMU || TARGET_arm || TARGET_xtensa)
 	help
 	help
 	  If you want to compile uClibc with NPTL support, then answer Y.
 	  If you want to compile uClibc with NPTL support, then answer Y.
 
 

+ 1 - 1
extra/Configs/Config.in.arch

@@ -20,7 +20,7 @@ config UCLIBC_FORMAT_ELF
 	select HAVE_LDSO
 	select HAVE_LDSO
 config UCLIBC_FORMAT_FDPIC_ELF
 config UCLIBC_FORMAT_FDPIC_ELF
 	bool "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
 	select DOPIC
 config UCLIBC_FORMAT_DSBT_ELF
 config UCLIBC_FORMAT_DSBT_ELF
 	bool "DBST ELF"
 	bool "DBST ELF"

+ 5 - 1
include/elf.h

@@ -3588,8 +3588,12 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_XTENSA_TLSDESC_FN	50
 #define R_XTENSA_TLSDESC_FN	50
 #define R_XTENSA_TLSDESC_ARG	51
 #define R_XTENSA_TLSDESC_ARG	51
 #define R_XTENSA_TLS_TPOFF	53
 #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.  */
 /* Keep this the last entry.  */
-#define R_XTENSA_NUM		54
+#define R_XTENSA_NUM		77
 
 
 /* C6X specific relocs */
 /* C6X specific relocs */
 #define R_C6000_NONE		0
 #define R_C6000_NONE		0

+ 1 - 0
ldso/ldso/xtensa/dl-inlines.h

@@ -0,0 +1 @@
+#include "../fdpic/dl-inlines.h"

+ 90 - 1
ldso/ldso/xtensa/dl-startup.h

@@ -7,6 +7,68 @@
  * Parts taken from glibc/sysdeps/xtensa/dl-machine.h.
  * 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
 #ifndef L_rcrt1
 __asm__ (
 __asm__ (
     "	.text\n"
     "	.text\n"
@@ -83,6 +145,7 @@ __asm__ (
     "	bnez    a6, 3b\n"
     "	bnez    a6, 3b\n"
     "	j      .Lfixup_stack_ret");
     "	j      .Lfixup_stack_ret");
 #endif
 #endif
+#endif /* __FDPIC__ */
 
 
 /* Get a pointer to the argv value.  */
 /* Get a pointer to the argv value.  */
 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
 #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.  */
 /* Function calls are not safe until the GOT relocations have been done.  */
 #define NO_FUNCS_BEFORE_BOOTSTRAP
 #define NO_FUNCS_BEFORE_BOOTSTRAP
 
 
-#if defined(__ARCH_USE_MMU__)
+#if defined(__ARCH_USE_MMU__) && !defined(__FDPIC__)
 #define PERFORM_BOOTSTRAP_GOT(tpnt) \
 #define PERFORM_BOOTSTRAP_GOT(tpnt) \
 do { \
 do { \
 	xtensa_got_location *got_loc; \
 	xtensa_got_location *got_loc; \
@@ -128,3 +191,29 @@ do { \
 	} \
 	} \
 } while (0)
 } while (0)
 #endif
 #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__ */

+ 65 - 1
ldso/ldso/xtensa/dl-sysdep.h

@@ -26,6 +26,7 @@
    in l_info array.  */
    in l_info array.  */
 #define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM)
 #define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM)
 
 
+#ifndef __FDPIC__
 typedef struct xtensa_got_location_struct {
 typedef struct xtensa_got_location_struct {
   Elf32_Off offset;
   Elf32_Off offset;
   Elf32_Word length;
   Elf32_Word length;
@@ -86,6 +87,7 @@ typedef struct xtensa_got_location_struct {
     else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ)			\
     else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ)			\
       dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val;		\
       dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val;		\
   } while (0)
   } while (0)
+#endif
 
 
 /* Here we define the magic numbers that this dynamic loader should accept. */
 /* Here we define the magic numbers that this dynamic loader should accept. */
 #define MAGIC1 EM_XTENSA
 #define MAGIC1 EM_XTENSA
@@ -115,10 +117,41 @@ elf_machine_dynamic (void)
   return (Elf32_Addr) &_DYNAMIC;
   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.  */
 /* Return the run-time load address of the shared object.  */
 static __always_inline Elf32_Addr
 static __always_inline Elf32_Addr
 elf_machine_load_address (void)
 elf_machine_load_address (void)
 {
 {
+#ifdef __FDPIC__
+  return 0;
+#else
   Elf32_Addr addr, tmp;
   Elf32_Addr addr, tmp;
 
 
   /* At this point, the runtime linker is being bootstrapped and the GOT
   /* 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));
 	   : "=a" (addr), "=a" (tmp));
 
 
   return addr - 3;
   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
 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_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;
   Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
   while (relative_count--)
   while (relative_count--)
@@ -149,3 +212,4 @@ elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
       rpnt++;
       rpnt++;
     }
     }
 }
 }
+#endif

+ 8 - 2
ldso/ldso/xtensa/dl-tlsdesc.S

@@ -24,6 +24,9 @@
 
 
 	.text
 	.text
 HIDDEN_ENTRY (_dl_tlsdesc_return)
 HIDDEN_ENTRY (_dl_tlsdesc_return)
+#ifdef __FDPIC__
+	l32i		a2, a2, 4
+#endif
 	rur.threadptr	a3
 	rur.threadptr	a3
 	add		a2, a2, a3
 	add		a2, a2, a3
 	abi_ret
 	abi_ret
@@ -53,7 +56,9 @@ END (_dl_tlsdesc_return)
 	 */
 	 */
 
 
 HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
 HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
-
+#ifdef __FDPIC__
+	l32i	a2, a2, 4
+#endif
 	/* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
 	/* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
 	rur.threadptr	a3
 	rur.threadptr	a3
 	l32i	a4, a3, 0
 	l32i	a4, a3, 0
@@ -86,7 +91,8 @@ HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
 	addi	a1, a1, -16
 	addi	a1, a1, -16
 	s32i	a0, a1, 0
 	s32i	a0, a1, 0
-	movi	a0, __tls_get_addr
+	movi	a0, JUMPTARGET(__tls_get_addr)
+	FDPIC_LOAD_JUMPTARGET(a0, a11, a0)
 	callx0	a0
 	callx0	a0
 	l32i	a0, a1, 0
 	l32i	a0, a1, 0
 	addi	a1, a1, 16
 	addi	a1, a1, 16

+ 89 - 25
ldso/ldso/xtensa/elfinterp.c

@@ -36,6 +36,13 @@
 #include "tlsdeschtab.h"
 #include "tlsdeschtab.h"
 #endif
 #endif
 
 
+#ifdef __FDPIC__
+unsigned long
+_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
+{
+	return 0;
+}
+#else
 unsigned long
 unsigned long
 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 _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;
 	return (unsigned long) new_addr;
 }
 }
-
+#endif
 
 
 static int
 static int
 _dl_parse (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 _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 reloc_type;
 	int symtab_index;
 	int symtab_index;
 	char *symname;
 	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
 #endif
 	struct symbol_ref sym_ref;
 	struct symbol_ref sym_ref;
 	ElfW(Addr) *reloc_addr;
 	ElfW(Addr) *reloc_addr;
@@ -155,7 +162,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	ElfW(Addr) old_val;
 	ElfW(Addr) old_val;
 #endif
 #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);
 	reloc_type = ELF_R_TYPE (rpnt->r_info);
 	symtab_index = ELF_R_SYM (rpnt->r_info);
 	symtab_index = ELF_R_SYM (rpnt->r_info);
 	sym_ref.sym = &symtab[symtab_index];
 	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;
 	symname = strtab + sym_ref.sym->st_name;
 
 
 	if (symtab_index) {
 	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
 		 * 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],
 			_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
 						&sym_ref, elf_machine_type_class(reloc_type));
 						&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
 #endif
 	} else {
 	} else {
 		symbol_addr =symtab[symtab_index].st_value;
 		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
 #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_GLOB_DAT:
 	case R_XTENSA_JMP_SLOT:
 	case R_XTENSA_JMP_SLOT:
+	case R_XTENSA_SYM32:
 		*reloc_addr = symbol_addr + rpnt->r_addend;
 		*reloc_addr = symbol_addr + rpnt->r_addend;
 		break;
 		break;
 
 
@@ -219,19 +235,63 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		break;
 		break;
 
 
 	case R_XTENSA_RELATIVE:
 	case R_XTENSA_RELATIVE:
-		*reloc_addr += tpnt->loadaddr + rpnt->r_addend;
+		*reloc_addr += DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_addend);
 		break;
 		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
 #if defined USE_TLS && USE_TLS
 	case R_XTENSA_TLS_TPOFF:
 	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;
 		break;
 	case R_XTENSA_TLSDESC_FN:
 	case R_XTENSA_TLSDESC_FN:
 #ifndef SHARED
 #ifndef SHARED
-		CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+		CHECK_STATIC_TLS((struct link_map *) def_mod);
 #else
 #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;
 			*reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic;
 		else
 		else
 #endif
 #endif
@@ -239,25 +299,25 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		break;
 		break;
 	case R_XTENSA_TLSDESC_ARG:
 	case R_XTENSA_TLSDESC_ARG:
 #ifndef SHARED
 #ifndef SHARED
-		CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+		CHECK_STATIC_TLS((struct link_map *) def_mod);
 #else
 #else
-		if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+		if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
 			*reloc_addr = (ElfW(Addr))
 			*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);
 							 symbol_addr + rpnt->r_addend);
 		else
 		else
 #endif
 #endif
 			*reloc_addr = symbol_addr + rpnt->r_addend +
 			*reloc_addr = symbol_addr + rpnt->r_addend +
-				tls_tpnt->l_tls_offset;
+				def_mod->l_tls_offset;
 		break;
 		break;
 #endif
 #endif
-
+#endif
 	default:
 	default:
 		return -1; /* Calls _dl_exit(1).  */
 		return -1; /* Calls _dl_exit(1).  */
 	}
 	}
 #if defined (__SUPPORT_LD_DEBUG__)
 #if defined (__SUPPORT_LD_DEBUG__)
 	if (_dl_debug_reloc && _dl_debug_detail)
 	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);
 					 old_val, *reloc_addr, reloc_addr);
 #endif
 #endif
 
 
@@ -275,7 +335,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	ElfW(Addr) old_val;
 	ElfW(Addr) old_val;
 #endif
 #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);
 	reloc_type = ELF_R_TYPE (rpnt->r_info);
 
 
 #if defined (__SUPPORT_LD_DEBUG__)
 #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:
 	case R_XTENSA_JMP_SLOT:
 		/* Perform a RELATIVE reloc on the GOT entry that transfers
 		/* Perform a RELATIVE reloc on the GOT entry that transfers
 		   to the stub function.  */
 		   to the stub function.  */
-		*reloc_addr += tpnt->loadaddr;
+		*reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, *reloc_addr);
 		break;
 		break;
 	case R_XTENSA_NONE:
 	case R_XTENSA_NONE:
 		break;
 		break;
@@ -296,7 +356,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 
 
 #if defined (__SUPPORT_LD_DEBUG__)
 #if defined (__SUPPORT_LD_DEBUG__)
 	if (_dl_debug_reloc && _dl_debug_detail)
 	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);
 					 old_val, *reloc_addr, reloc_addr);
 #endif
 #endif
 	return 0;
 	return 0;
@@ -320,3 +380,7 @@ _dl_parse_relocation_information (struct dyn_elf *rpnt,
 	return _dl_parse (rpnt->dyn, scope, rel_addr, rel_size,
 	return _dl_parse (rpnt->dyn, scope, rel_addr, rel_size,
 					  _dl_do_reloc);
 					  _dl_do_reloc);
 }
 }
+
+#ifndef IS_IN_libdl
+# include "../../libc/sysdeps/linux/xtensa/crtreloc.c"
+#endif

+ 5 - 1
libc/sysdeps/linux/xtensa/__start_context.S

@@ -22,9 +22,10 @@
  * There's no entry instruction, makecontext sets up ucontext_t as if
  * There's no entry instruction, makecontext sets up ucontext_t as if
  * getcontext was called above and is about to return here.
  * getcontext was called above and is about to return here.
  * Registers on entry to this function:
  * 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
  *   a13: ucp->uc_link, next context to activate if func returns
  *   a14: func argc
  *   a14: func argc
+ *   a15: current GOT pointer (in case of FDPIC)
  */
  */
 	.literal_position
 	.literal_position
 
 
@@ -46,14 +47,17 @@ ENTRY_PREFIX(__start_context)
 	addi	a1, a1, 16
 	addi	a1, a1, 16
 	/* func arguments 6..argc - 1 are now at the top of the stack */
 	/* func arguments 6..argc - 1 are now at the top of the stack */
 1:
 1:
+	FDPIC_LOAD_FUNCDESC (a12, a12)
 	callx0	a12
 	callx0	a12
 	beqz	a13, 1f
 	beqz	a13, 1f
 	mov	a2, a13
 	mov	a2, a13
 	movi	a4, JUMPTARGET (setcontext)
 	movi	a4, JUMPTARGET (setcontext)
+	FDPIC_LOAD_JUMPTARGET (a4, a15, a4)
 	callx0	a4
 	callx0	a4
 1:
 1:
 	movi	a4, JUMPTARGET (_exit)
 	movi	a4, JUMPTARGET (_exit)
 	movi	a2, 0
 	movi	a2, 0
+	FDPIC_LOAD_JUMPTARGET (a4, a15, a4)
 	callx0	a4
 	callx0	a4
 	ill
 	ill
 END(__start_context)
 END(__start_context)

+ 117 - 0
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 */

+ 6 - 0
libc/sysdeps/linux/xtensa/clone.S

@@ -81,11 +81,17 @@ ENTRY (__clone)
 	callx4	a2
 	callx4	a2
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
 	mov	a2, a9			/* load up the 'arg' parameter */
 	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 */
 	callx0	a7			/* call the user's function */
 
 
 	/* Call _exit.  Note that any return parameter from the user's
 	/* Call _exit.  Note that any return parameter from the user's
 	   function in a2 is seen as inputs to _exit.  */
 	   function in a2 is seen as inputs to _exit.  */
 	movi	a0, JUMPTARGET(_exit)
 	movi	a0, JUMPTARGET(_exit)
+	FDPIC_LOAD_JUMPTARGET(a0, a12, a0)
 	callx0	a0
 	callx0	a0
 #else
 #else
 #error Unsupported Xtensa ABI
 #error Unsupported Xtensa ABI

+ 81 - 0
libc/sysdeps/linux/xtensa/crt1.S

@@ -35,6 +35,86 @@
 
 
 #include <features.h>
 #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__
 #ifndef __UCLIBC_CTOR_DTOR__
         .weak _init
         .weak _init
         .weak _fini
         .weak _fini
@@ -173,3 +253,4 @@ __data_start:
 	.long	0
 	.long	0
 	.weak	data_start
 	.weak	data_start
 	data_start = __data_start
 	data_start = __data_start
+#endif /* defined(__FDPIC__) */

+ 8 - 0
libc/sysdeps/linux/xtensa/crti.S

@@ -11,6 +11,10 @@ _init:
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
 	addi	sp, sp, -16
 	addi	sp, sp, -16
 	s32i	a0, sp, 0
 	s32i	a0, sp, 0
+#ifdef __FDPIC__
+	s32i	a12, sp, 4
+	mov	a12, a11
+#endif
 #else
 #else
 #error Unsupported Xtensa ABI
 #error Unsupported Xtensa ABI
 #endif
 #endif
@@ -26,6 +30,10 @@ _fini:
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
 	addi	sp, sp, -16
 	addi	sp, sp, -16
 	s32i	a0, sp, 0
 	s32i	a0, sp, 0
+#ifdef __FDPIC__
+	s32i	a12, sp, 4
+	mov	a12, a11
+#endif
 #else
 #else
 #error Unsupported Xtensa ABI
 #error Unsupported Xtensa ABI
 #endif
 #endif

+ 6 - 0
libc/sysdeps/linux/xtensa/crtn.S

@@ -4,6 +4,9 @@
 #if defined(__XTENSA_WINDOWED_ABI__)
 #if defined(__XTENSA_WINDOWED_ABI__)
 	retw
 	retw
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
+#ifdef __FDPIC__
+	l32i	a12, sp, 4
+#endif
 	l32i	a0, sp, 0
 	l32i	a0, sp, 0
 	addi	sp, sp, 16
 	addi	sp, sp, 16
 	ret
 	ret
@@ -15,6 +18,9 @@
 #if defined(__XTENSA_WINDOWED_ABI__)
 #if defined(__XTENSA_WINDOWED_ABI__)
 	retw
 	retw
 #elif defined(__XTENSA_CALL0_ABI__)
 #elif defined(__XTENSA_CALL0_ABI__)
+#ifdef __FDPIC__
+	l32i	a12, sp, 4
+#endif
 	l32i	a0, sp, 0
 	l32i	a0, sp, 0
 	addi	sp, sp, 16
 	addi	sp, sp, 16
 	ret
 	ret

+ 105 - 0
libc/sysdeps/linux/xtensa/crtreloc.c

@@ -0,0 +1,105 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   written by Alexandre Oliva <aoliva@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__ */

+ 1 - 0
libc/sysdeps/linux/xtensa/getcontext.S

@@ -33,6 +33,7 @@ ENTRY(__getcontext)
 	addi	a4, a2, UCONTEXT_SIGMASK
 	addi	a4, a2, UCONTEXT_SIGMASK
 	movi	a2, SIG_BLOCK
 	movi	a2, SIG_BLOCK
 	movi	a5, JUMPTARGET (sigprocmask)
 	movi	a5, JUMPTARGET (sigprocmask)
+	FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
 	jx	a5
 	jx	a5
 END(__getcontext)
 END(__getcontext)
 #elif defined(__XTENSA_WINDOWED_ABI__)
 #elif defined(__XTENSA_WINDOWED_ABI__)

+ 5 - 0
libc/sysdeps/linux/xtensa/makecontext.c

@@ -73,7 +73,12 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
     sp -= 4 * (argc + 2);
     sp -= 4 * (argc + 2);
   sp &= -16;
   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;
   ucp->uc_mcontext.sc_pc = (unsigned long) __start_context;
+#endif
   ucp->uc_mcontext.sc_a[1] = sp;
   ucp->uc_mcontext.sc_a[1] = sp;
   ucp->uc_mcontext.sc_a[12] = (unsigned long) func;
   ucp->uc_mcontext.sc_a[12] = (unsigned long) func;
   ucp->uc_mcontext.sc_a[13] = (unsigned long) ucp->uc_link;
   ucp->uc_mcontext.sc_a[13] = (unsigned long) ucp->uc_link;

+ 1 - 0
libc/sysdeps/linux/xtensa/setcontext.S

@@ -28,6 +28,7 @@ ENTRY(__setcontext)
 	movi	a4, 0
 	movi	a4, 0
 	movi	a2, SIG_SETMASK
 	movi	a2, SIG_SETMASK
 	movi	a5, JUMPTARGET (sigprocmask)
 	movi	a5, JUMPTARGET (sigprocmask)
+	FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
 	callx0	a5
 	callx0	a5
 	bnez	a2, .Lerror
 	bnez	a2, .Lerror
 
 

+ 2 - 1
libc/sysdeps/linux/xtensa/setjmp.S

@@ -155,7 +155,8 @@ ENTRY (__sigsetjmp)
 	s32i	a14, a2, 16
 	s32i	a14, a2, 16
 	s32i	a15, a2, 20
 	s32i	a15, a2, 20
 	mov	a12, a2
 	mov	a12, a2
-	movi	a0, __sigjmp_save
+	movi	a0, JUMPTARGET(__sigjmp_save)
+	FDPIC_LOAD_JUMPTARGET(a0, a11, a0)
 	callx0	a0
 	callx0	a0
 	l32i	a0, a12, 0
 	l32i	a0, a12, 0
 	l32i	a12, a12, 8
 	l32i	a12, a12, 8

+ 1 - 0
libc/sysdeps/linux/xtensa/swapcontext.S

@@ -36,6 +36,7 @@ ENTRY(__swapcontext)
 	addi	a4, a2, UCONTEXT_SIGMASK
 	addi	a4, a2, UCONTEXT_SIGMASK
 	movi	a2, SIG_SETMASK
 	movi	a2, SIG_SETMASK
 	movi	a5, JUMPTARGET (sigprocmask)
 	movi	a5, JUMPTARGET (sigprocmask)
+	FDPIC_LOAD_JUMPTARGET (a5, a11, a5)
 	callx0	a5
 	callx0	a5
 	bnez	a2, .Lerror
 	bnez	a2, .Lerror
 
 

+ 45 - 3
libc/sysdeps/linux/xtensa/sysdep.h

@@ -75,13 +75,27 @@
 #define LITERAL_POSITION .literal_position
 #define LITERAL_POSITION .literal_position
 
 
 #undef JUMPTARGET
 #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
 /* 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
    it doesn't hurt to use it conditionally for PIC code in case that
    changes someday.  */
    changes someday.  */
 #define JUMPTARGET(name) name##@PLT
 #define JUMPTARGET(name) name##@PLT
+#define FDPIC_LOAD_FUNCDESC(call_target, funcdesc)
+#define FDPIC_LOAD_JUMPTARGET(call_target, got_base, jumptarget)
 #else
 #else
 #define JUMPTARGET(name) name
 #define JUMPTARGET(name) name
+#define FDPIC_LOAD_FUNCDESC(call_target, funcdesc)
+#define FDPIC_LOAD_JUMPTARGET(call_target, got_base, jumptarget)
 #endif
 #endif
 
 
 #ifndef FRAMESIZE
 #ifndef FRAMESIZE
@@ -153,6 +167,21 @@
 
 
 #if defined _LIBC_REENTRANT
 #if defined _LIBC_REENTRANT
 # if defined USE___THREAD
 # 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_ERRNO errno
 #  define SYSCALL_ERROR_HANDLER						      \
 #  define SYSCALL_ERROR_HANDLER						      \
 0:	rur	a4, THREADPTR;						      \
 0:	rur	a4, THREADPTR;						      \
@@ -162,13 +191,14 @@
 	s32i	a2, a4, 0;						      \
 	s32i	a2, a4, 0;						      \
 	movi	a2, -1;							      \
 	movi	a2, -1;							      \
 	j	.Lpseudo_end;
 	j	.Lpseudo_end;
+#endif
 # else /* !USE___THREAD */
 # else /* !USE___THREAD */
 
 
 #if defined(__XTENSA_WINDOWED_ABI__)
 #if defined(__XTENSA_WINDOWED_ABI__)
 #  define SYSCALL_ERROR_HANDLER						      \
 #  define SYSCALL_ERROR_HANDLER						      \
 0:	neg	a2, a2;							      \
 0:	neg	a2, a2;							      \
 	mov	a6, a2;							      \
 	mov	a6, a2;							      \
-	movi	a4, __errno_location@PLT;				      \
+	movi	a4, JUMPTARGET(__errno_location);			      \
 	callx4	a4;						              \
 	callx4	a4;						              \
 	s32i	a2, a6, 0;						      \
 	s32i	a2, a6, 0;						      \
 	movi	a2, -1;							      \
 	movi	a2, -1;							      \
@@ -179,7 +209,8 @@
 	addi	a1, a1, -16;						      \
 	addi	a1, a1, -16;						      \
 	s32i	a0, a1, 0;						      \
 	s32i	a0, a1, 0;						      \
 	s32i	a2, a1, 4;						      \
 	s32i	a2, a1, 4;						      \
-	movi	a0, __errno_location@PLT;				      \
+	movi	a0, JUMPTARGET(__errno_location);			      \
+	FDPIC_LOAD_JUMPTARGET(a0, a11, a0);				      \
 	callx0	a0;						              \
 	callx0	a0;						              \
 	l32i	a0, a1, 0;						      \
 	l32i	a0, a1, 0;						      \
 	l32i	a3, a1, 4;						      \
 	l32i	a3, a1, 4;						      \
@@ -193,12 +224,23 @@
 
 
 # endif /* !USE___THREAD */
 # endif /* !USE___THREAD */
 #else /* !_LIBC_REENTRANT */
 #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						      \
 #define SYSCALL_ERROR_HANDLER						      \
 0:	movi	a4, errno;						      \
 0:	movi	a4, errno;						      \
 	neg	a2, a2;							      \
 	neg	a2, a2;							      \
 	s32i	a2, a4, 0;						      \
 	s32i	a2, a4, 0;						      \
 	movi	a2, -1;							      \
 	movi	a2, -1;							      \
 	j	.Lpseudo_end;
 	j	.Lpseudo_end;
+#endif /* __FDPIC__ */
 #endif /* _LIBC_REENTRANT */
 #endif /* _LIBC_REENTRANT */
 
 
 #endif	/* __ASSEMBLER__ */
 #endif	/* __ASSEMBLER__ */

+ 2 - 0
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-syscall.S = -D_LIBC_REENTRANT
 ASFLAGS-mmap.S = -D_LIBC_REENTRANT
 ASFLAGS-mmap.S = -D_LIBC_REENTRANT
+
+ASFLAGS += -DUSE___THREAD

+ 24 - 9
libpthread/nptl/sysdeps/xtensa/dl-tls.h

@@ -28,6 +28,29 @@ typedef struct
 
 
 extern void *__tls_get_addr (tls_index *ti);
 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.  */
 /* Type used to represent a TLS descriptor.  */
 struct tlsdesc
 struct tlsdesc
 {
 {
@@ -39,19 +62,11 @@ struct tlsdesc
   ptrdiff_t (*entry)(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
 extern ptrdiff_t attribute_hidden
   _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *);
   _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *);
 
 
 extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
 extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
 extern ptrdiff_t attribute_hidden
 extern ptrdiff_t attribute_hidden
   _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *);
   _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *);
-
+#endif
 #endif
 #endif