diff options
Diffstat (limited to 'ports')
-rw-r--r-- | ports/ChangeLog.arm | 4 | ||||
-rw-r--r-- | ports/sysdeps/arm/arm-features.h | 13 | ||||
-rw-r--r-- | ports/sysdeps/arm/memcpy.S | 29 | ||||
-rw-r--r-- | ports/sysdeps/arm/memmove.S | 29 |
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 |