about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/reloc.h4
-rw-r--r--ldso/dynlink.c7
-rw-r--r--src/ldso/arm/tlsdesc.S62
3 files changed, 72 insertions, 1 deletions
diff --git a/arch/arm/reloc.h b/arch/arm/reloc.h
index 4b00bf64..2c2e7f58 100644
--- a/arch/arm/reloc.h
+++ b/arch/arm/reloc.h
@@ -26,7 +26,9 @@
 #define REL_DTPMOD      R_ARM_TLS_DTPMOD32
 #define REL_DTPOFF      R_ARM_TLS_DTPOFF32
 #define REL_TPOFF       R_ARM_TLS_TPOFF32
-//#define REL_TLSDESC     R_ARM_TLS_DESC
+#define REL_TLSDESC     R_ARM_TLS_DESC
+
+#define TLSDESC_BACKWARDS
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
 	"mov sp,%1 ; bx %0" : : "r"(pc), "r"(sp) : "memory" )
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 3ecbddfa..c2892b90 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -458,6 +458,13 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 					+ addend;
 #endif
 			}
+#ifdef TLSDESC_BACKWARDS
+			/* Some archs (32-bit ARM at least) invert the order of
+			 * the descriptor members. Fix them up here. */
+			size_t tmp = reloc_addr[0];
+			reloc_addr[0] = reloc_addr[1];
+			reloc_addr[1] = tmp;
+#endif
 			break;
 		default:
 			error("Error relocating %s: unsupported relocation type %d",
diff --git a/src/ldso/arm/tlsdesc.S b/src/ldso/arm/tlsdesc.S
new file mode 100644
index 00000000..f3d67fce
--- /dev/null
+++ b/src/ldso/arm/tlsdesc.S
@@ -0,0 +1,62 @@
+.syntax unified
+
+.text
+.global __tlsdesc_static
+.hidden __tlsdesc_static
+.type __tlsdesc_static,%function
+__tlsdesc_static:
+	ldr r0,[r0]
+	bx lr
+
+.hidden __tls_get_new
+
+.global __tlsdesc_dynamic
+.hidden __tlsdesc_dynamic
+.type __tlsdesc_dynamic,%function
+__tlsdesc_dynamic:
+	push {r2,r3,ip,lr}
+	ldr r1,[r0]
+	ldr r2,[r1,#4]  // r2 = offset
+	ldr r1,[r1]     // r1 = modid
+
+	ldr r0,1f
+	add r0,r0,pc
+	ldr r0,[r0]
+2:
+#if __ARM_ARCH >= 5
+	blx r0          // r0 = tp
+#else
+	mov lr,pc
+	bx r0
+#endif
+	ldr r3,[r0,#-4] // r3 = dtv
+	ldr ip,[r3]     // ip = dtv slot count
+	cmp r1,ip
+	bhi 3f
+	ldr ip,[r3,r1,LSL #2]
+	sub r0,ip,r0
+	add r0,r0,r2    // r0 = r3[r1]-r0+r2
+4:
+#if __ARM_ARCH >= 5
+	pop {r2,r3,ip,pc}
+#else
+	pop {r2,r3,ip,lr}
+	bx lr
+#endif
+
+3:
+#if __ARM_PCS_VFP || !__SOFTFP__
+	vpush {d0-d7}
+#endif
+	push {r0-r3}
+	add r0,sp,#4
+	bl __tls_get_new
+	pop {r1-r3,ip}
+#if __ARM_PCS_VFP || !__SOFTFP__
+	vpop {d0-d7}
+#endif
+	sub r0,r0,r1    // r0 = retval-tp
+	b 4b
+
+	.align 2
+1:	.word __a_gettp_ptr - 2b