]> granicus.if.org Git - musl/commitdiff
add TLSDESC support for 32-bit arm
authorRich Felker <dalias@aerifal.cx>
Mon, 1 Oct 2018 22:37:02 +0000 (18:37 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 1 Oct 2018 22:37:02 +0000 (18:37 -0400)
unlike other asm where the baseline ISA is used, these functions are
hot paths and use ISA-level specializations.

call-clobbered vfp registers are saved before calling __tls_get_new,
since there is no guarantee it won't use them. while setjmp/longjmp
have to use hwcap to decide whether to the fpu is in use, since
application code could be using vfp registers even if libc was
compiled as pure softfloat, __tls_get_new is part of libc and can be
assumed not to have access to vfp registers if tlsdesc.S does not.
thus it suffices just to check the predefined preprocessor macros. the
check for __ARM_PCS_VFP is redundant; !__SOFTFP__ must always be true
if the target ISA level includes fpu instructions/registers.

arch/arm/reloc.h
ldso/dynlink.c
src/ldso/arm/tlsdesc.S [new file with mode: 0644]

index 4b00bf645e8cf98d115fa24accaaa2fb69f20ff0..2c2e7f58f968cd4478d980bde4a4e1a2da09f136 100644 (file)
@@ -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" )
index 3ecbddfab0c5768b06f90d3256adad07a563d5e5..c2892b9032d7fbc2e1002cc4b08d0a73f9750598 100644 (file)
@@ -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 (file)
index 0000000..f3d67fc
--- /dev/null
@@ -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