aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@hack.frob.com>2013-03-13 09:40:55 -0700
committerRoland McGrath <roland@hack.frob.com>2013-03-13 09:40:55 -0700
commit9e1d4ac924d66f4cfbcca3e98bd1bd62a5d92d5f (patch)
treebaa6554df6a97af7c9e8502835daa9e87e106fc7
parent9dc7c64f932f22278bb34b18f855956755106fd0 (diff)
downloadglibc-9e1d4ac924d66f4cfbcca3e98bd1bd62a5d92d5f.zip
glibc-9e1d4ac924d66f4cfbcca3e98bd1bd62a5d92d5f.tar.gz
glibc-9e1d4ac924d66f4cfbcca3e98bd1bd62a5d92d5f.tar.bz2
ARM: Support avoiding pc as destination register.
-rw-r--r--ports/ChangeLog.arm7
-rw-r--r--ports/sysdeps/arm/arm-features.h4
-rw-r--r--ports/sysdeps/arm/memcpy.S29
-rw-r--r--ports/sysdeps/arm/memmove.S29
4 files changed, 67 insertions, 2 deletions
diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm
index 2e250f7..72060ba 100644
--- a/ports/ChangeLog.arm
+++ b/ports/ChangeLog.arm
@@ -1,3 +1,10 @@
+2013-03-13 Roland McGrath <roland@hack.frob.com>
+
+ * sysdeps/arm/arm-features.h: Add comment about ARM_ALWAYS_BX.
+ * sysdeps/arm/memcpy.S: Include <arm-features.h>.
+ [ARM_ALWAYS_BX]: Avoid pc as destination.
+ * sysdeps/arm/memmove.S: Likewise.
+
2013-03-12 Roland McGrath <roland@hack.frob.com>
* sysdeps/arm/armv6t2/memchr.S [NO_THUMB]:
diff --git a/ports/sysdeps/arm/arm-features.h b/ports/sysdeps/arm/arm-features.h
index 31801cf..139a403 100644
--- a/ports/sysdeps/arm/arm-features.h
+++ b/ports/sysdeps/arm/arm-features.h
@@ -36,4 +36,8 @@
at runtime (or that we never care about its state) and so need not
be checked for. */
+/* A more-specific arm-features.h file may define ARM_ALWAYS_BX to indicate
+ that instructions using pc as a destination register must never be used,
+ so a "bx" (or "blx") instruction is always required. */
+
#endif /* arm-features.h */
diff --git a/ports/sysdeps/arm/memcpy.S b/ports/sysdeps/arm/memcpy.S
index eb9699d..779f403 100644
--- a/ports/sysdeps/arm/memcpy.S
+++ b/ports/sysdeps/arm/memcpy.S
@@ -20,6 +20,7 @@
/* Thumb requires excessive IT insns here. */
#define NO_THUMB
#include <sysdep.h>
+#include <arm-features.h>
/*
* Data preload for architectures that support it (ARM V5TE and above)
@@ -89,7 +90,12 @@ ENTRY(memcpy)
CALGN( bcs 2f )
CALGN( adr r4, 6f )
CALGN( subs r2, r2, r3 ) @ C gets set
+#ifndef ARM_ALWAYS_BX
CALGN( add pc, r4, ip )
+#else
+ CALGN( add r4, r4, ip )
+ CALGN( bx r4 )
+#endif
PLD( pld [r1, #0] )
2: PLD( subs r2, r2, #96 )
@@ -108,8 +114,17 @@ ENTRY(memcpy)
5: ands ip, r2, #28
rsb ip, ip, #32
+#ifndef ARM_ALWAYS_BX
addne pc, pc, ip @ C is always clear here
b 7f
+#else
+ beq 7f
+ push {r10}
+ cfi_adjust_cfa_offset (4)
+ cfi_rel_offset (r10, 0)
+ add r10, pc, ip
+ bx r10
+#endif
6: nop
ldr r3, [r1], #4
ldr r4, [r1], #4
@@ -119,8 +134,13 @@ ENTRY(memcpy)
ldr r8, [r1], #4
ldr lr, [r1], #4
+#ifndef ARM_ALWAYS_BX
add pc, pc, ip
nop
+#else
+ add r10, pc, ip
+ bx r10
+#endif
nop
str r3, [r0], #4
str r4, [r0], #4
@@ -130,6 +150,12 @@ ENTRY(memcpy)
str r8, [r0], #4
str lr, [r0], #4
+#ifdef ARM_ALWAYS_BX
+ pop {r10}
+ cfi_adjust_cfa_offset (-4)
+ cfi_restore (r10)
+#endif
+
CALGN( bcs 2b )
7: pop {r5 - r8}
@@ -147,7 +173,8 @@ ENTRY(memcpy)
strbcs r4, [r0], #1
strbcs ip, [r0]
-#if defined (__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)
+#if ((defined (__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)) \
+ || defined (ARM_ALWAYS_BX))
pop {r0, r4, lr}
cfi_adjust_cfa_offset (-12)
cfi_restore (r4)
diff --git a/ports/sysdeps/arm/memmove.S b/ports/sysdeps/arm/memmove.S
index 9e8ad65..4a2cb92 100644
--- a/ports/sysdeps/arm/memmove.S
+++ b/ports/sysdeps/arm/memmove.S
@@ -20,6 +20,7 @@
/* Thumb requires excessive IT insns here. */
#define NO_THUMB
#include <sysdep.h>
+#include <arm-features.h>
/*
* Data preload for architectures that support it (ARM V5TE and above)
@@ -105,7 +106,12 @@ ENTRY(memmove)
CALGN( bcs 2f )
CALGN( adr r4, 6f )
CALGN( subs r2, r2, ip ) @ C is set here
+#ifndef ARM_ALWAYS_BX
CALGN( add pc, r4, ip )
+#else
+ CALGN( add r4, r4, ip )
+ CALGN( bx r4 )
+#endif
PLD( pld [r1, #-4] )
2: PLD( subs r2, r2, #96 )
@@ -124,8 +130,17 @@ ENTRY(memmove)
5: ands ip, r2, #28
rsb ip, ip, #32
+#ifndef ARM_ALWAYS_BX
addne pc, pc, ip @ C is always clear here
b 7f
+#else
+ beq 7f
+ push {r10}
+ cfi_adjust_cfa_offset (4)
+ cfi_rel_offset (r10, 0)
+ add r10, pc, ip
+ bx r10
+#endif
6: nop
ldr r3, [r1, #-4]!
ldr r4, [r1, #-4]!
@@ -135,8 +150,13 @@ ENTRY(memmove)
ldr r8, [r1, #-4]!
ldr lr, [r1, #-4]!
+#ifndef ARM_ALWAYS_BX
add pc, pc, ip
nop
+#else
+ add r10, pc, ip
+ bx r10
+#endif
nop
str r3, [r0, #-4]!
str r4, [r0, #-4]!
@@ -146,6 +166,12 @@ ENTRY(memmove)
str r8, [r0, #-4]!
str lr, [r0, #-4]!
+#ifdef ARM_ALWAYS_BX
+ pop {r10}
+ cfi_adjust_cfa_offset (-4)
+ cfi_restore (r10)
+#endif
+
CALGN( bcs 2b )
7: pop {r5 - r8}
@@ -163,7 +189,8 @@ ENTRY(memmove)
strbcs r4, [r0, #-1]!
strbcs ip, [r0, #-1]
-#if defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)
+#if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
+ || defined (ARM_ALWAYS_BX))
pop {r0, r4, lr}
cfi_adjust_cfa_offset (-12)
cfi_restore (r4)