summaryrefslogtreecommitdiff
path: root/rtl/arm
diff options
context:
space:
mode:
authorkaroly <karoly@3ad0048d-3df7-0310-abae-a5850022a9f2>2015-10-16 18:53:35 +0000
committerkaroly <karoly@3ad0048d-3df7-0310-abae-a5850022a9f2>2015-10-16 18:53:35 +0000
commita8fe62a18c7aa20f2ac7d89ebacde3f29735630b (patch)
treebe43677fc6e477c61787646dc68c42344ad456c8 /rtl/arm
parenta11b000d9674a5e7833d80fde959efa6714a48a3 (diff)
downloadfpc-a8fe62a18c7aa20f2ac7d89ebacde3f29735630b.tar.gz
fix InterlockedCompareExchange on ARM-Linux: kuser_cmpxchg destroys r3, which needs to be restored, if we have to loop
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@32063 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'rtl/arm')
-rw-r--r--rtl/arm/arm.inc12
1 files changed, 7 insertions, 5 deletions
diff --git a/rtl/arm/arm.inc b/rtl/arm/arm.inc
index bfdb7fc94a..ba70889392 100644
--- a/rtl/arm/arm.inc
+++ b/rtl/arm/arm.inc
@@ -970,8 +970,6 @@ asm
{$else}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {r4, lr}
- mvn r3, #0x0000f000
- sub r3, r3, #0x3F
mov r4, r2 // Swap parameters around
mov r2, r0
@@ -979,9 +977,13 @@ asm
// r1 and r2 will not be clobbered by kuser_cmpxchg
// If we have to loop, r0 will be set to the original Comperand
+ // kuser_cmpxchg is documented to destroy r3, therefore setting
+ // r3 must be in the loop
.Linterlocked_compare_exchange_loop:
+ mvn r3, #0x0000f000
+ sub r3, r3, #0x3F
{$ifdef CPUARM_HAS_BLX}
- blx r3 // Call kuser_cmpxchg, sets C-Flag on success
+ blx r3 // Call kuser_cmpxchg, sets C-Flag on success
{$else}
mov lr, pc
{$ifdef CPUARM_HAS_BX}
@@ -997,11 +999,11 @@ asm
// The loop case is HIGHLY unlikely, it would require that we got rescheduled between
// calling kuser_cmpxchg and the ldr. While beeing rescheduled another process/thread
// would have the set the value to our comperand
- ldr r0, [r2] // Load the currently set value
+ ldr r0, [r2] // Load the currently set value
cmp r0, r4 // Return if Comperand != current value, otherwise loop again
ldmnefd r13!, {r4, pc}
// If we need to loop here, we have to
- b .Linterlocked_compare_exchange_loop
+ b .Linterlocked_compare_exchange_loop
{$else}
// lock