arm: Introduce and use GET_TLS
authorRichard Henderson <rth@twiddle.net>
Thu, 14 Feb 2013 04:10:45 +0000 (20:10 -0800)
committerRichard Henderson <rth@twiddle.net>
Wed, 6 Mar 2013 15:46:38 +0000 (07:46 -0800)
Factor out the sequence needed to call kuser_get_tls, as we can't
play subtract into pc games in thumb mode.  Prepare for hard-tp,
pulling the save of LR into the macro.

ports/ChangeLog.arm
ports/sysdeps/arm/dl-tlsdesc.S
ports/sysdeps/arm/sysdep.h
ports/sysdeps/unix/arm/sysdep.S
ports/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S
ports/sysdeps/unix/sysv/linux/arm/clone.S
ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S
ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h
ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S
ports/sysdeps/unix/sysv/linux/arm/sysdep.h

index b5c9ef3..3ad5704 100644 (file)
@@ -1,5 +1,18 @@
 2013-03-06  Richard Henderson <rth@redhat.com>
 
+       * sysdeps/arm/sysdep.h (GET_TLS): New macro.
+       * sysdeps/arm/dl-tlsdesc.S (_dl_tlsdesc_undefweak): Use it.
+       (_dl_tlsdesc_dynamic): Likewise.
+       * sysdeps/unix/arm/sysdep.S (__syscall_error): Likewise.
+       * sysdeps/unix/sysv/linux/arm/sysdep.h (GET_TLS): New macro.
+       * sysdeps/unix/sysv/linux/arm/clone.S (__clone): Likewise.
+       * sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S (SAVE_PID): Likewise.
+       * sysdeps/unix/sysv/linux/arm/nptl/vfork.S (SAVE_PID): Likewise.
+       * sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S (__aeabi_read_tp):
+       Add thumb2 alternative.
+
        * sysdeps/arm/sysdep.h (NEGOFF_ADJ_BASE): New macro.
        (NEGOFF_ADJ_BASE2, NEGOFF_OFF1, NEGOFF_OFF2): New macros.
        * sysdeps/unix/sysv/linux/arm/clone.S (__clone): Use them.
index 7b4c8df..1a15272 100644 (file)
@@ -50,18 +50,9 @@ _dl_tlsdesc_return:
        .fnstart
        .align 2
 _dl_tlsdesc_undefweak:
-       @ Are we allowed a misaligned stack pointer calling read_tp?
-       .save   {lr}
-       stmdb   sp!, {lr}
-       cfi_adjust_cfa_offset (4)
-       cfi_rel_offset (lr,0)
-       bl      __aeabi_read_tp
+       GET_TLS (r1)
        rsb     r0, r0, #0
-       ldmia   sp!, {lr}
-       cfi_adjust_cfa_offset (-4)
-       cfi_restore (lr)
        BX      (lr)
-
        cfi_endproc
        .fnend
        .size   _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
@@ -106,7 +97,7 @@ _dl_tlsdesc_dynamic:
        cfi_rel_offset (r4,8)
        cfi_rel_offset (lr,12)
        ldr     r1, [r0] /* td */
-       bl      __aeabi_read_tp
+       GET_TLS (lr)
        mov     r4, r0 /* r4 = tp */
        ldr     r0, [r0]
        ldr     r2, [r1, #8] /* gen_count */
index 9230131..c525d5b 100644 (file)
 #  define NEGOFF_OFF1(R, OFF)          [R, $OFF]
 #  define NEGOFF_OFF2(R, OFFA, OFFB)   [R, $OFFA]
 # endif
+
+/* Helper to get the TLS base pointer.  The interface is that TMP is a
+   register that may be used to hold the LR, if necessary.  TMP may be
+   LR itself to indicate that LR need not be saved.  The base pointer
+   is returned in R0.  Only R0 and TMP are modified.
+
+   At this generic level we have no tricks to pull.  Call the ABI routine.  */
+# define GET_TLS(TMP)                                  \
+       push    { r1, r2, r3, lr };                     \
+       cfi_remember_state;                             \
+       cfi_adjust_cfa_offset (16);                     \
+       cfi_rel_offset (r1, 0);                         \
+       cfi_rel_offset (r2, 4);                         \
+       cfi_rel_offset (r3, 8);                         \
+       cfi_rel_offset (lr, 12);                        \
+       bl      __aeabi_read_tp;                        \
+       pop     { r1, r2, r3, lr };                     \
+       cfi_restore_state
+
 #endif /* __ASSEMBLER__ */
 
 /* This number is the offset from the pc at the current location.  */
index d44ee48..d82ad25 100644 (file)
@@ -37,14 +37,8 @@ __syscall_error:
 #endif
 
 #ifndef IS_IN_rtld
-       mov ip, lr
-       cfi_register (lr, ip)
-       mov r1, r0
-
-       mov r0, #0xffff0fff
-       mov lr, pc
-       sub pc, r0, #31
-
+       mov     r1, r0
+       GET_TLS (r2)
        ldr     r2, 1f
 #ifdef __thumb__
 2:     add     r2, r2, pc
@@ -54,7 +48,7 @@ __syscall_error:
 #endif
        str     r1, [r0, r2]
        mvn     r0, #0
-       DO_RET(ip)
+       DO_RET(lr)
 
 1:     .word errno(gottpoff) + (. - 2b - PC_OFS)
 #elif RTLD_PRIVATE_ERRNO
index c4ddbc6..ecdc322 100644 (file)
 
        .hidden __aeabi_read_tp
 ENTRY (__aeabi_read_tp)
+#ifdef __thumb2__
+       movw    r0, #0x0fe0
+       movt    r0, #0xffff
+       bx      r0
+#else
        mov     r0, #0xffff0fff
        sub     pc, r0, #31
+#endif
 END (__aeabi_read_tp)
index 653bd74..9009393 100644 (file)
@@ -74,9 +74,7 @@ PSEUDO_END (__clone)
 #ifdef RESET_PID
        tst     ip, #CLONE_THREAD
        bne     3f
-       mov     r0, #0xffff0fff
-       mov     lr, pc
-       sub     pc, r0, #31
+       GET_TLS (lr)
        mov     r1, r0
        tst     ip, #CLONE_VM
        ldr     r7, =SYS_ify(getpid)
index f79bb66..ca50457 100644 (file)
 
 /* Save the PID value.  */
 #define SAVE_PID \
-       str     lr, [sp, #-4]!;         /* Save LR.  */                 \
-       cfi_adjust_cfa_offset (4);                                      \
-       cfi_rel_offset (lr, 0);                                         \
-       mov     r0, #0xffff0fff;        /* Point to the high page.  */  \
-       mov     lr, pc;                 /* Save our return address.  */ \
-       sub     pc, r0, #31;            /* Jump to the TLS entry.  */   \
-       ldr     lr, [sp], #4;           /* Restore LR.  */              \
-       cfi_adjust_cfa_offset (-4);                                     \
-       cfi_restore (lr);                                               \
+       GET_TLS (r2);                                                   \
        NEGOFF_ADJ_BASE2 (r2, r0, PID_OFFSET); /* Save the TLS addr in r2. */ \
        ldr     r3, NEGOFF_OFF1 (r2, PID_OFFSET); /* Load the saved PID.  */  \
        rsb     r0, r3, #0;             /* Negate it.  */                    \
index 9157d03..2fc0535 100644 (file)
@@ -216,7 +216,7 @@ extern int __local_multiple_threads attribute_hidden;
        stmfd   sp!, {r0, lr};                                          \
        cfi_adjust_cfa_offset (8);                                      \
        cfi_rel_offset (lr, 4);                                         \
-       bl      __aeabi_read_tp;                                        \
+       GET_TLS (lr);                                                   \
        NEGOFF_ADJ_BASE (r0, MULTIPLE_THREADS_OFFSET);                  \
        ldr     ip, NEGOFF_OFF1 (r0, MULTIPLE_THREADS_OFFSET);          \
        ldmfd   sp!, {r0, lr};                                          \
index 1c6f3bb..216fb2d 100644 (file)
 
 /* Save the PID value.  */
 #define SAVE_PID \
-       str     lr, [sp, #-4]!;         /* Save LR.  */                 \
-       cfi_adjust_cfa_offset (4);                                      \
-       cfi_rel_offset (lr, 0);                                         \
-       mov     r0, #0xffff0fff;        /* Point to the high page.  */  \
-       mov     lr, pc;                 /* Save our return address.  */ \
-       sub     pc, r0, #31;            /* Jump to the TLS entry.  */   \
-       ldr     lr, [sp], #4;           /* Restore LR.  */              \
-       cfi_adjust_cfa_offset (-4);                                     \
-       cfi_restore (lr);                                               \
+       GET_TLS (r2);                                                   \
        NEGOFF_ADJ_BASE2 (r2, r0, PID_OFFSET); /* Save the TLS addr in r2.  */ \
        ldr     r3, NEGOFF_OFF1 (r2, PID_OFFSET); /* Load the saved PID.  */   \
        rsbs    r0, r3, #0;             /* Negate it.  */                     \
index 89208a9..dc2058b 100644 (file)
 
 #ifdef __ASSEMBLER__
 
+/* Internal macro calling the linux kernel kuser_get_tls helper.
+   Note that in thumb mode, a constant pool break is often out of range, so
+   we always expand the constant inline.  */
+#ifdef __thumb2__
+# define GET_TLS_BODY                  \
+       movw    r0, #0x0fe0;            \
+       movt    r0, #0xffff;            \
+       blx     r0
+#else
+# define GET_TLS_BODY \
+       mov     r0, #0xffff0fff;        /* Point to the high page.  */  \
+       mov     lr, pc;                 /* Save our return address.  */ \
+       sub     pc, r0, #31             /* Jump to the TLS entry.  */
+#endif
+
+/* Helper to get the TLS base pointer.  Save LR in TMP, return in R0,
+   and no other registers clobbered.  TMP may be LR itself to indicate
+   that no save is necessary.  */
+#undef GET_TLS
+#define GET_TLS(TMP)                   \
+  .ifnc TMP, lr;                       \
+       mov     TMP, lr;                \
+       cfi_register (lr, TMP);         \
+       GET_TLS_BODY;                   \
+       mov     lr, TMP;                \
+       cfi_restore (lr);               \
+  .else;                               \
+       GET_TLS_BODY;                   \
+  .endif
+
 /* Linux uses a negative return value to indicate syscall errors,
    unlike most Unices, which use the condition codes' carry flag.