Add support for pointer mangling in glibc internal structures in C
and assembler code.
ports/ChangeLog.arm:
2013-09-27 Will Newton <will.newton@linaro.org>
* 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.
---
ports/sysdeps/arm/__longjmp.S | 14 +++++++++++
ports/sysdeps/arm/include/bits/setjmp.h | 5 ++--
ports/sysdeps/arm/jmpbuf-unwind.h | 13 +++++++++-
ports/sysdeps/arm/setjmp.S | 14 +++++++++++
ports/sysdeps/arm/sysdep.h | 11 +++++++++
ports/sysdeps/unix/sysv/linux/arm/sysdep.h | 39 +++++++++++++++++++++++++++---
6 files changed, 90 insertions(+), 6 deletions(-)
Changes in v2:
- Use a global instead of a thread local variable to store the guard value
- The bit I don't like in this version of the patch is the test for !IS_IN_nscd,
but without it I get undefined references to __pointer_chk_guard_local.
diff --git a/ports/sysdeps/arm/__longjmp.S b/ports/sysdeps/arm/__longjmp.S
index a5edede..2b1f7f4 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 1559d7b..64505dc 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 0863540..1b0d020 100644
--- a/ports/sysdeps/arm/jmpbuf-unwind.h
+++ b/ports/sysdeps/arm/jmpbuf-unwind.h
@@ -17,6 +17,7 @@
#include <setjmp.h>
#include <stdint.h>
+#include <sysdep.h>
#include <unwind.h>
/* 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 a6c161d..b38b919 100644
--- a/ports/sysdeps/arm/setjmp.S
+++ b/ports/sysdeps/arm/setjmp.S
@@ -24,11 +24,25 @@
#include <arm-features.h>
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 5501597..60d26fd 100644
--- a/ports/sysdeps/arm/sysdep.h
+++ b/ports/sysdeps/arm/sysdep.h
@@ -171,6 +171,17 @@
99: OP R, [pc, T]
# endif
+# 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 b195d8e..7ef8374 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/sysdep.h
+++ b/ports/sysdeps/unix/sysv/linux/arm/sysdep.h
@@ -435,8 +435,41 @@ __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 IS_IN_nscd)
+# 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)
+# 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)
+# 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 */
--
1.8.1.4