diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm index a84c7d211c..0724dbd9a0 100644 --- a/ports/ChangeLog.arm +++ b/ports/ChangeLog.arm @@ -1,3 +1,18 @@ +2013-10-03 Will Newton + + * sysdeps/arm/__longjmp.S (__longjmp): Demangle fp, sp + and lr when restoring register values. + * sysdeps/arm/include/bits/setjmp.h (JMP_BUF_REGLIST): Remove + sp and lr from list and replace fp with a4. + * sysdeps/arm/jmpbuf-unwind.h (_jmpbuf_sp): New function. + (_JMPBUF_UNWINDS_ADJ): Call _jmpbuf_sp. + * sysdeps/arm/setjmp.S (__sigsetjmp): Mangle fp, sp and lr + before storing register values. + * sysdeps/arm/sysdep.h (LDST_GLOBAL): New macro. + * sysdeps/unix/sysv/linux/arm/sysdep.h (PTR_MANGLE): New macro. + (PTR_DEMANGLE): Likewise. (PTR_MANGLE2): Likewise. + (PTR_DEMANGLE2): Likewise. + 2013-09-24 Will Newton * ports/sysdeps/arm/nptl/tls.h (TLS_INIT_TP_EXPENSIVE): Remove diff --git a/ports/sysdeps/arm/__longjmp.S b/ports/sysdeps/arm/__longjmp.S index a5edede16d..2b1f7f41c1 100644 --- a/ports/sysdeps/arm/__longjmp.S +++ b/ports/sysdeps/arm/__longjmp.S @@ -34,10 +34,24 @@ ENTRY (__longjmp) sfi_breg ip, \ ldr r4, [\B, #32] /* jmpbuf's sp */ cfi_undefined (r4) +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (r4, r4, a3, a4) +#endif CHECK_SP (r4) #endif sfi_sp sfi_breg ip, \ ldmia \B!, JMP_BUF_REGLIST +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (fp, a4, a3, a2) + ldr a4, [ip], #4 + PTR_DEMANGLE2 (sp, a4, a3) + ldr a4, [ip], #4 + PTR_DEMANGLE2 (lr, a4, a3) +#else + mov fp, a4 + ldr sp, [ip], #4 + ldr lr, [ip], #4 +#endif cfi_restore (v1) cfi_restore (v2) cfi_restore (v3) diff --git a/ports/sysdeps/arm/include/bits/setjmp.h b/ports/sysdeps/arm/include/bits/setjmp.h index 1559d7b8e6..64505dcb94 100644 --- a/ports/sysdeps/arm/include/bits/setjmp.h +++ b/ports/sysdeps/arm/include/bits/setjmp.h @@ -26,8 +26,9 @@ #ifndef _ISOMAC /* Register list for a ldm/stm instruction to load/store - the general registers from a __jmp_buf. */ -# define JMP_BUF_REGLIST {v1-v6, sl, fp, sp, lr} + the general registers from a __jmp_buf. The a4 register + contains fp at this point. */ +# define JMP_BUF_REGLIST {a4, v1-v6, sl} /* Index of __jmp_buf where the sp register resides. */ # define __JMP_BUF_SP 8 diff --git a/ports/sysdeps/arm/jmpbuf-unwind.h b/ports/sysdeps/arm/jmpbuf-unwind.h index 0863540ce0..1b0d0202e3 100644 --- a/ports/sysdeps/arm/jmpbuf-unwind.h +++ b/ports/sysdeps/arm/jmpbuf-unwind.h @@ -17,6 +17,7 @@ #include #include +#include #include /* Test if longjmp to JMPBUF would unwind the frame @@ -27,8 +28,18 @@ #define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) +static inline uintptr_t __attribute__ ((unused)) +_jmpbuf_sp (__jmp_buf regs) +{ + uintptr_t sp = regs[__JMP_BUF_SP]; +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (sp); +#endif + return sp; +} + #define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ - ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj)) + ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj)) /* We use the normal longjmp for unwinding. */ #define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/ports/sysdeps/arm/setjmp.S b/ports/sysdeps/arm/setjmp.S index a6c161db54..b38b919af0 100644 --- a/ports/sysdeps/arm/setjmp.S +++ b/ports/sysdeps/arm/setjmp.S @@ -24,11 +24,25 @@ #include ENTRY (__sigsetjmp) +#ifdef PTR_MANGLE + PTR_MANGLE (a4, fp, a3, ip) +#else + mov a4, fp +#endif mov ip, r0 /* Save registers */ sfi_breg ip, \ stmia \B!, JMP_BUF_REGLIST +#ifdef PTR_MANGLE + PTR_MANGLE2 (a4, sp, a3) + str a4, [ip], #4 + PTR_MANGLE2 (a4, lr, a3) + str a4, [ip], #4 +#else + str sp, [ip], #4 + str lr, [ip], #4 +#endif #if !defined ARM_ASSUME_NO_IWMMXT || defined __SOFTFP__ # define NEED_HWCAP 1 diff --git a/ports/sysdeps/arm/sysdep.h b/ports/sysdeps/arm/sysdep.h index 550159740b..3823617f13 100644 --- a/ports/sysdeps/arm/sysdep.h +++ b/ports/sysdeps/arm/sysdep.h @@ -171,6 +171,18 @@ 99: OP R, [pc, T] # endif +/* Load or store to/from a global EXPR into/from R, using T. */ +# define LDST_GLOBAL(OP, R, T, EXPR) \ + ldr T, 99f; \ + ldr R, 100f; \ +98: add T, T, pc; \ + ldr T, [T, R]; \ + .subsection 2; \ +99: .word _GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS; \ +100: .word EXPR##(GOT); \ + .previous; \ + OP R, [T] + /* 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, diff --git a/ports/sysdeps/unix/sysv/linux/arm/sysdep.h b/ports/sysdeps/unix/sysv/linux/arm/sysdep.h index b195d8ea1d..6cfe4e08a7 100644 --- a/ports/sysdeps/unix/sysv/linux/arm/sysdep.h +++ b/ports/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -435,8 +435,44 @@ __local_syscall_error: \ #endif /* __ASSEMBLER__ */ -/* Pointer mangling is not yet supported for ARM. */ -#define PTR_MANGLE(var) (void) (var) -#define PTR_DEMANGLE(var) (void) (var) +/* Pointer mangling support. */ +#if (defined NOT_IN_libc && defined IS_IN_rtld) || \ + (!defined SHARED && (!defined NOT_IN_libc || defined IS_IN_libpthread)) +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(dst, src, guard, tmp) \ + LDST_PCREL(ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard_local)); \ + PTR_MANGLE2(dst, src, guard) +/* Use PTR_MANGLE2 for efficiency if guard is already loaded. */ +# define PTR_MANGLE2(dst, src, guard) \ + eor dst, src, guard +# define PTR_DEMANGLE(dst, src, guard, tmp) \ + PTR_MANGLE (dst, src, guard, tmp) +# define PTR_DEMANGLE2(dst, src, guard) \ + PTR_MANGLE2 (dst, src, guard) +# else +extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden; +# define PTR_MANGLE(var) \ + (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local) +# define PTR_DEMANGLE(var) PTR_MANGLE (var) +# endif +#else +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(dst, src, guard, tmp) \ + LDST_GLOBAL(ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard)); \ + PTR_MANGLE2(dst, src, guard) +/* Use PTR_MANGLE2 for efficiency if guard is already loaded. */ +# define PTR_MANGLE2(dst, src, guard) \ + eor dst, src, guard +# define PTR_DEMANGLE(dst, src, guard, tmp) \ + PTR_MANGLE (dst, src, guard, tmp) +# define PTR_DEMANGLE2(dst, src, guard) \ + PTR_MANGLE2 (dst, src, guard) +# else +extern uintptr_t __pointer_chk_guard attribute_relro; +# define PTR_MANGLE(var) \ + (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard) +# define PTR_DEMANGLE(var) PTR_MANGLE (var) +# endif +#endif #endif /* linux/arm/sysdep.h */