From: Richard Henderson Date: Thu, 14 Feb 2013 04:10:45 +0000 (-0800) Subject: arm: Introduce and use GET_TLS X-Git-Tag: upstream/2.30~9410 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5232b909bf31420497ec864e34f806a545017185;p=external%2Fglibc.git arm: Introduce and use GET_TLS 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. --- diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm index b5c9ef3..3ad5704 100644 --- a/ports/ChangeLog.arm +++ b/ports/ChangeLog.arm @@ -1,5 +1,18 @@ 2013-03-06 Richard Henderson + * 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. diff --git a/ports/sysdeps/arm/dl-tlsdesc.S b/ports/sysdeps/arm/dl-tlsdesc.S index 7b4c8df..1a15272 100644 --- a/ports/sysdeps/arm/dl-tlsdesc.S +++ b/ports/sysdeps/arm/dl-tlsdesc.S @@ -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 */ diff --git a/ports/sysdeps/arm/sysdep.h b/ports/sysdeps/arm/sysdep.h index 9230131..c525d5b 100644 --- a/ports/sysdeps/arm/sysdep.h +++ b/ports/sysdeps/arm/sysdep.h @@ -150,6 +150,25 @@ # 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. */ diff --git a/ports/sysdeps/unix/arm/sysdep.S b/ports/sysdeps/unix/arm/sysdep.S index d44ee48..d82ad25 100644 --- a/ports/sysdeps/unix/arm/sysdep.S +++ b/ports/sysdeps/unix/arm/sysdep.S @@ -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 diff --git a/ports/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S b/ports/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S index c4ddbc6..ecdc322 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S +++ b/ports/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S @@ -41,6 +41,12 @@ .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) diff --git a/ports/sysdeps/unix/sysv/linux/arm/clone.S b/ports/sysdeps/unix/sysv/linux/arm/clone.S index 653bd74..9009393 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/clone.S +++ b/ports/sysdeps/unix/sysv/linux/arm/clone.S @@ -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) diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S b/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S index f79bb66..ca50457 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S @@ -19,15 +19,7 @@ /* 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. */ \ diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h b/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h index 9157d03..2fc0535 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h @@ -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}; \ diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S b/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S index 1c6f3bb..216fb2d 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S @@ -19,15 +19,7 @@ /* 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. */ \ diff --git a/ports/sysdeps/unix/sysv/linux/arm/sysdep.h b/ports/sysdeps/unix/sysv/linux/arm/sysdep.h index 89208a9..dc2058b 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/sysdep.h +++ b/ports/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -45,6 +45,36 @@ #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.