fix __aeabi_read_tp oversight in arm atomics/tls overhaul
authorRich Felker <dalias@aerifal.cx>
Sat, 22 Nov 2014 17:26:38 +0000 (12:26 -0500)
committerRich Felker <dalias@aerifal.cx>
Sat, 22 Nov 2014 17:26:38 +0000 (12:26 -0500)
calls to __aeabi_read_tp may be generated by the compiler to access
TLS on pre-v6 targets. previously, this function was hard-coded to
call the kuser helper, which would crash on kernels with kuser helper
removed.

to fix the problem most efficiently, the definition of __aeabi_read_tp
is moved so that it's an alias for the new __a_gettp. however, on v7+
targets, code to initialize the runtime choice of thread-pointer
loading code is not even compiled, meaning that defining
__aeabi_read_tp would have caused an immediate crash due to using the
default implementation of __a_gettp with a HCF instruction.

fortunately there is an elegant solution which reduces overall code
size: putting the native thread-pointer loading instruction in the
default code path for __a_gettp, so that separate default/native code
paths are not needed. this function should never be called before
__set_thread_area anyway, and if it is called early on pre-v6
hardware, the old behavior (crashing) is maintained.

ideally __aeabi_read_tp would not be called at all on v7+ targets
anyway -- in fact, prior to the overhaul, the same problem existed,
but it was never caught by users building for v7+ with kuser disabled.
however, it's possible for calls to __aeabi_read_tp to end up in a v7+
binary if some of the object files were built for pre-v7 targets, e.g.
in the case of static libraries that were built separately, so this
case needs to be handled.

arch/arm/src/__set_thread_area.c
arch/arm/src/arm/atomics.s
src/thread/arm/tls.s [deleted file]

index 680510eab0464bce6e9726a1eac3f8d527f3d2c1..61d02827b5c1420c197fe287b99aac4e237e80b9 100644 (file)
@@ -9,7 +9,7 @@ extern const unsigned char __attribute__((__visibility__("hidden")))
        __a_barrier_dummy[], __a_barrier_oldkuser[],
        __a_barrier_v6[], __a_barrier_v7[],
        __a_cas_dummy[], __a_cas_v6[], __a_cas_v7[],
-       __a_gettp_dummy[], __a_gettp_native[];
+       __a_gettp_dummy[];
 
 #define __a_barrier_kuser 0xffff0fa0
 #define __a_cas_kuser 0xffff0fc0
@@ -26,7 +26,6 @@ int __set_thread_area(void *p)
 #if !__ARM_ARCH_7A__ && !__ARM_ARCH_7R__ && __ARM_ARCH < 7
        if (__hwcap & HWCAP_TLS) {
                size_t *aux;
-               SET(gettp, native);
                SET(cas, v7);
                SET(barrier, v7);
                for (aux=libc.auxv; *aux; aux+=2) {
index 9fcc7bd749d3a761e70d9d528d1588532fb1612b..f241cc027c123f3fe7573c8395197cb8ae79be2a 100644 (file)
@@ -81,6 +81,10 @@ __a_cas_v7:
        .word 0xf57ff05b        /* dmb ish */
        bx lr
 
+.global __aeabi_read_tp
+.type __aeabi_read_tp,%function
+__aeabi_read_tp:
+
 .global __a_gettp
 .hidden __a_gettp
 .type __a_gettp,%function
@@ -92,10 +96,6 @@ __a_gettp:
 .global __a_gettp_dummy
 .hidden __a_gettp_dummy
 __a_gettp_dummy:
-       .word 0xe7fddef1
-.global __a_gettp_native
-.hidden __a_gettp_native
-__a_gettp_native:
        mrc p15,0,r0,c13,c0,3
        bx lr
 
diff --git a/src/thread/arm/tls.s b/src/thread/arm/tls.s
deleted file mode 100644 (file)
index 59736ac..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.global __aeabi_read_tp
-.type __aeabi_read_tp,%function
-__aeabi_read_tp:
-       ldr pc,=0xffff0fe0