diff options
Diffstat (limited to 'ports/sysdeps')
-rw-r--r-- | ports/sysdeps/arm/arm-features.h | 4 | ||||
-rw-r--r-- | ports/sysdeps/arm/memcpy.S | 29 | ||||
-rw-r--r-- | ports/sysdeps/arm/memmove.S | 29 |
3 files changed, 60 insertions, 2 deletions
diff --git a/ports/sysdeps/arm/arm-features.h b/ports/sysdeps/arm/arm-features.h index 31801cf408..139a40368b 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 eb9699ddf6..779f403576 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 9e8ad65f44..4a2cb92ea4 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) |