From 5232b909bf31420497ec864e34f806a545017185 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 20:10:45 -0800 Subject: [PATCH] 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. --- ports/ChangeLog.arm | 13 ++++++++ ports/sysdeps/arm/dl-tlsdesc.S | 13 ++------ ports/sysdeps/arm/sysdep.h | 19 ++++++++++++ ports/sysdeps/unix/arm/sysdep.S | 12 ++------ .../unix/sysv/linux/arm/aeabi_read_tp.S | 6 ++++ ports/sysdeps/unix/sysv/linux/arm/clone.S | 4 +-- .../unix/sysv/linux/arm/nptl/pt-vfork.S | 10 +------ .../unix/sysv/linux/arm/nptl/sysdep-cancel.h | 2 +- .../sysdeps/unix/sysv/linux/arm/nptl/vfork.S | 10 +------ ports/sysdeps/unix/sysv/linux/arm/sysdep.h | 30 +++++++++++++++++++ 10 files changed, 77 insertions(+), 42 deletions(-) diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm index b5c9ef3347..3ad5704e2f 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 7b4c8dfcb5..1a15272821 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 9230131c78..c525d5b977 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 d44ee4869a..d82ad258a0 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 c4ddbc69ff..ecdc3228a3 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 653bd74102..9009393f33 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 f79bb66f2b..ca50457070 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 9157d03270..2fc053523f 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 1c6f3bb2bf..216fb2d2eb 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 89208a9f19..dc2058b275 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.