about summary refs log tree commit diff
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/ChangeLog.arm4
-rw-r--r--ports/sysdeps/arm/arm-features.h13
-rw-r--r--ports/sysdeps/arm/memcpy.S29
-rw-r--r--ports/sysdeps/arm/memmove.S29
4 files changed, 63 insertions, 12 deletions
diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm
index 71520a6344..878eb60828 100644
--- a/ports/ChangeLog.arm
+++ b/ports/ChangeLog.arm
@@ -1,5 +1,9 @@
 2013-03-13  Roland McGrath  <roland@hack.frob.com>
 
+	* sysdeps/arm/arm-features.h (ARM_BX_ALIGN_LOG2): New macro.
+	* sysdeps/arm/memcpy.S: Respect ARM_BX_ALIGN_LOG2.
+	* sysdeps/arm/memmove.S: Likewise.
+
 	* sysdeps/arm/add_n.S: Include <arm-features.h>.
 	[ARM_ALWAYS_BX]: Don't pop into pc.
 
diff --git a/ports/sysdeps/arm/arm-features.h b/ports/sysdeps/arm/arm-features.h
index 139a40368b..5104ba3329 100644
--- a/ports/sysdeps/arm/arm-features.h
+++ b/ports/sysdeps/arm/arm-features.h
@@ -40,4 +40,17 @@
    that instructions using pc as a destination register must never be used,
    so a "bx" (or "blx") instruction is always required.  */
 
+/* The log2 of the minimum alignment required for an address that
+   is the target of a computed branch (i.e. a "bx" instruction).
+   A more-specific arm-features.h file may define this to set a more
+   stringent requirement.
+
+   Using this only makes sense for code in ARM mode (where instructions
+   always have a fixed size of four bytes), or for Thumb-mode code that is
+   specifically aligning all the related branch targets to match (since
+   Thumb instructions might be either two or four bytes).  */
+#ifndef ARM_BX_ALIGN_LOG2
+# define ARM_BX_ALIGN_LOG2	2
+#endif
+
 #endif  /* arm-features.h */
diff --git a/ports/sysdeps/arm/memcpy.S b/ports/sysdeps/arm/memcpy.S
index 779f403576..926581434e 100644
--- a/ports/sysdeps/arm/memcpy.S
+++ b/ports/sysdeps/arm/memcpy.S
@@ -91,9 +91,9 @@ ENTRY(memcpy)
 	CALGN(	adr	r4, 6f			)
 	CALGN(	subs	r2, r2, r3		)  @ C gets set
 #ifndef ARM_ALWAYS_BX
-	CALGN(	add	pc, r4, ip		)
+	CALGN(	add	pc, r4, ip, lsl	#(ARM_BX_ALIGN_LOG2 - 2))
 #else
-	CALGN(	add	r4, r4, ip		)
+	CALGN(	add	r4, r4, ip, lsl	#(ARM_BX_ALIGN_LOG2 - 2))
 	CALGN(	bx	r4			)
 #endif
 
@@ -115,39 +115,56 @@ ENTRY(memcpy)
 5:		ands	ip, r2, #28
 		rsb	ip, ip, #32
 #ifndef ARM_ALWAYS_BX
-		addne	pc, pc, ip		@ C is always clear here
+		/* C is always clear here.  */
+		addne	pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		b	7f
 #else
 		beq	7f
 		push	{r10}
 		cfi_adjust_cfa_offset (4)
 		cfi_rel_offset (r10, 0)
-		add	r10, pc, ip
+		add	r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		bx	r10
 #endif
+		.p2align ARM_BX_ALIGN_LOG2
 6:		nop
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r3, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r4, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r5, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r6, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r7, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r8, [r1], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	lr, [r1], #4
 
 #ifndef ARM_ALWAYS_BX
-		add	pc, pc, ip
+		add	pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		nop
 #else
-		add	r10, pc, ip
+		add	r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		bx	r10
 #endif
+		.p2align ARM_BX_ALIGN_LOG2
 		nop
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r3, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r4, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r5, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r6, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r7, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r8, [r0], #4
+		.p2align ARM_BX_ALIGN_LOG2
 		str	lr, [r0], #4
 
 #ifdef ARM_ALWAYS_BX
diff --git a/ports/sysdeps/arm/memmove.S b/ports/sysdeps/arm/memmove.S
index 4a2cb92ea4..96b27cfefc 100644
--- a/ports/sysdeps/arm/memmove.S
+++ b/ports/sysdeps/arm/memmove.S
@@ -107,9 +107,9 @@ ENTRY(memmove)
 	CALGN(	adr	r4, 6f			)
 	CALGN(	subs	r2, r2, ip		)  @ C is set here
 #ifndef ARM_ALWAYS_BX
-	CALGN(	add	pc, r4, ip		)
+	CALGN(	add	pc, r4, ip, lsl	#(ARM_BX_ALIGN_LOG2 - 2))
 #else
-	CALGN(	add	r4, r4, ip		)
+	CALGN(	add	r4, r4, ip, lsl	#(ARM_BX_ALIGN_LOG2 - 2))
 	CALGN(	bx	r4			)
 #endif
 
@@ -131,39 +131,56 @@ ENTRY(memmove)
 5:		ands	ip, r2, #28
 		rsb	ip, ip, #32
 #ifndef ARM_ALWAYS_BX
-		addne	pc, pc, ip		@ C is always clear here
+		/* C is always clear here.  */
+		addne	pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		b	7f
 #else
 		beq	7f
 		push	{r10}
 		cfi_adjust_cfa_offset (4)
 		cfi_rel_offset (r10, 0)
-		add	r10, pc, ip
+		add	r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		bx	r10
 #endif
+		.p2align ARM_BX_ALIGN_LOG2
 6:		nop
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r3, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r4, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r5, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r6, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r7, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	r8, [r1, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		ldr	lr, [r1, #-4]!
 
 #ifndef ARM_ALWAYS_BX
-		add	pc, pc, ip
+		add	pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		nop
 #else
-		add	r10, pc, ip
+		add	r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
 		bx	r10
 #endif
+		.p2align ARM_BX_ALIGN_LOG2
 		nop
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r3, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r4, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r5, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r6, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r7, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	r8, [r0, #-4]!
+		.p2align ARM_BX_ALIGN_LOG2
 		str	lr, [r0, #-4]!
 
 #ifdef ARM_ALWAYS_BX