diff options
-rw-r--r-- | ports/ChangeLog.arm | 8 | ||||
-rw-r--r-- | ports/sysdeps/arm/sysdep.h | 16 | ||||
-rw-r--r-- | ports/sysdeps/unix/sysv/linux/arm/clone.S | 5 | ||||
-rw-r--r-- | ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S | 11 | ||||
-rw-r--r-- | ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h | 3 | ||||
-rw-r--r-- | ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S | 14 |
6 files changed, 43 insertions, 14 deletions
diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm index d3da2fbb10..b5c9ef3347 100644 --- a/ports/ChangeLog.arm +++ b/ports/ChangeLog.arm @@ -1,5 +1,13 @@ 2013-03-06 Richard Henderson <rth@redhat.com> + * 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. + * sysdeps/unix/sysv/linux/arm/nptl/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S: Likewise. + * sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h (SINGLE_THREAD_P): + Likewise. + * sysdeps/arm/sysdep.h (LDST_PCREL): New macro. * sysdeps/unix/arm/sysdep.S (__syscall_error): Use LDST_PCREL. Fix up gottpoff load of errno for thumb2. diff --git a/ports/sysdeps/arm/sysdep.h b/ports/sysdeps/arm/sysdep.h index 29a78f043d..9230131c78 100644 --- a/ports/sysdeps/arm/sysdep.h +++ b/ports/sysdeps/arm/sysdep.h @@ -134,6 +134,22 @@ .previous; \ 99: OP R, [pc, T] # endif + +/* Cope with negative memory offsets, which thumb can't encode. + Use NEGOFF_ADJ_BASE to (conditionally) alter the base register, + and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm, + or NEGOFF_OFF2 to use A-B for thumb and A for arm. */ +# ifdef __thumb2__ +# define NEGOFF_ADJ_BASE(R, OFF) add R, R, $OFF +# define NEGOFF_ADJ_BASE2(D, S, OFF) add D, S, $OFF +# define NEGOFF_OFF1(R, OFF) [R] +# define NEGOFF_OFF2(R, OFFA, OFFB) [R, $((OFFA) - (OFFB))] +# else +# define NEGOFF_ADJ_BASE(R, OFF) +# define NEGOFF_ADJ_BASE2(D, S, OFF) mov D, S +# define NEGOFF_OFF1(R, OFF) [R, $OFF] +# define NEGOFF_OFF2(R, OFFA, OFFB) [R, $OFFA] +# endif #endif /* __ASSEMBLER__ */ /* This number is the offset from the pc at the current location. */ diff --git a/ports/sysdeps/unix/sysv/linux/arm/clone.S b/ports/sysdeps/unix/sysv/linux/arm/clone.S index 732a3ffd01..653bd74102 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/clone.S +++ b/ports/sysdeps/unix/sysv/linux/arm/clone.S @@ -83,8 +83,9 @@ PSEUDO_END (__clone) ite ne movne r0, #-1 swieq 0x0 - str r0, [r1, #PID_OFFSET] - str r0, [r1, #TID_OFFSET] + NEGOFF_ADJ_BASE (r1, TID_OFFSET) + str r0, NEGOFF_OFF1 (r1, TID_OFFSET) + str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET) 3: #endif @ pick the function arg and call address off the stack and execute 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 a38d56419c..f79bb66f2b 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S @@ -28,14 +28,15 @@ ldr lr, [sp], #4; /* Restore LR. */ \ cfi_adjust_cfa_offset (-4); \ cfi_restore (lr); \ - mov r2, r0; /* Save the TLS addr in r2. */ \ - ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ - rsb r0, r3, #0; /* Negate it. */ \ - str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + 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. */ \ + str r0, NEGOFF_OFF1 (r2, PID_OFFSET); /* Store the temp PID. */ /* Restore the old PID value in the parent. */ #define RESTORE_PID \ cmp r0, #0; /* If we are the parent... */ \ - strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + it ne; \ + strne r3, NEGOFF_OFF1 (r2, PID_OFFSET); /* restore the saved PID. */ #include "../vfork.S" 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 8889369ae3..9157d03270 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h @@ -217,7 +217,8 @@ extern int __local_multiple_threads attribute_hidden; cfi_adjust_cfa_offset (8); \ cfi_rel_offset (lr, 4); \ bl __aeabi_read_tp; \ - ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \ + NEGOFF_ADJ_BASE (r0, MULTIPLE_THREADS_OFFSET); \ + ldr ip, NEGOFF_OFF1 (r0, MULTIPLE_THREADS_OFFSET); \ ldmfd sp!, {r0, lr}; \ cfi_adjust_cfa_offset (-8); \ cfi_restore (lr); \ diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S b/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S index 3fce2d1afa..1c6f3bb2bf 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S @@ -28,15 +28,17 @@ ldr lr, [sp], #4; /* Restore LR. */ \ cfi_adjust_cfa_offset (-4); \ cfi_restore (lr); \ - mov r2, r0; /* Save the TLS addr in r2. */ \ - ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ - rsbs r0, r3, #0; /* Negate it. */ \ - moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \ - str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + 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. */ \ + it eq; \ + moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \ + str r0, NEGOFF_OFF1 (r2, PID_OFFSET); /* Store the temp PID. */ /* Restore the old PID value in the parent. */ #define RESTORE_PID \ cmp r0, #0; /* If we are the parent... */ \ - strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + it ne; \ + strne r3, NEGOFF_OFF1 (r2, PID_OFFSET); /* restore the saved PID. */ #include "../vfork.S" |