ARM: memmove: use frame pointer as unwind anchor
authorArd Biesheuvel <ardb@kernel.org>
Mon, 4 Oct 2021 09:29:11 +0000 (11:29 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 3 Dec 2021 14:11:32 +0000 (15:11 +0100)
The memmove routine is a bit unusual in the way it manages the stack
pointer: depending on the execution path through the function, the SP
assumes different values as different subsets of the register file are
preserved and restored again. This is problematic when it comes to EHABI
unwind info, as it is not instruction accurate, and does not allow
tracking the SP value as it changes.

Commit 207a6cb06990c ("ARM: 8224/1: Add unwinding support for memmove
function") addressed this by carving up the function in different chunks
as far as the unwinder is concerned, and keeping a set of unwind
directives for each of them, each corresponding with the state of the
stack pointer during execution of the chunk in question. This not only
duplicates unwind info unnecessarily, but it also complicates unwinding
the stack upon overflow.

Instead, let's do what the compiler does when the SP is updated halfway
through a function, which is to use a frame pointer and emit the
appropriate unwind directives to communicate this to the unwinder.

Note that Thumb-2 uses R7 for this, while ARM uses R11 aka FP. So let's
avoid touching R7 in the body of the function, so that Thumb-2 can use
it as the frame pointer. R11 was not modified in the first place.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Keith Packard <keithpac@amazon.com>
Tested-by: Marc Zyngier <maz@kernel.org>
Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
arch/arm/lib/memmove.S

index 6fecc12..6410554 100644 (file)
@@ -31,12 +31,13 @@ WEAK(memmove)
                subs    ip, r0, r1
                cmphi   r2, ip
                bls     __memcpy
-
-               stmfd   sp!, {r0, r4, lr}
        UNWIND( .fnend                          )
 
        UNWIND( .fnstart                        )
-       UNWIND( .save   {r0, r4, lr}            ) @ in first stmfd block
+       UNWIND( .save   {r0, r4, fpreg, lr}     )
+               stmfd   sp!, {r0, r4, UNWIND(fpreg,) lr}
+       UNWIND( .setfp  fpreg, sp               )
+       UNWIND( mov     fpreg, sp               )
                add     r1, r1, r2
                add     r0, r0, r2
                subs    r2, r2, #4
@@ -48,12 +49,7 @@ WEAK(memmove)
                bne     10f
 
 1:             subs    r2, r2, #(28)
-               stmfd   sp!, {r5 - r8}
-       UNWIND( .fnend                          )
-
-       UNWIND( .fnstart                        )
-       UNWIND( .save   {r0, r4, lr}            )
-       UNWIND( .save   {r5 - r8}               ) @ in second stmfd block
+               stmfd   sp!, {r5, r6, r8, r9}
                blt     5f
 
        CALGN(  ands    ip, r0, #31             )
@@ -72,9 +68,9 @@ WEAK(memmove)
        PLD(    pld     [r1, #-96]              )
 
 3:     PLD(    pld     [r1, #-128]             )
-4:             ldmdb   r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+4:             ldmdb   r1!, {r3, r4, r5, r6, r8, r9, ip, lr}
                subs    r2, r2, #32
-               stmdb   r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+               stmdb   r0!, {r3, r4, r5, r6, r8, r9, ip, lr}
                bge     3b
        PLD(    cmn     r2, #96                 )
        PLD(    bge     4b                      )
@@ -88,8 +84,8 @@ WEAK(memmove)
                W(ldr)  r4, [r1, #-4]!
                W(ldr)  r5, [r1, #-4]!
                W(ldr)  r6, [r1, #-4]!
-               W(ldr)  r7, [r1, #-4]!
                W(ldr)  r8, [r1, #-4]!
+               W(ldr)  r9, [r1, #-4]!
                W(ldr)  lr, [r1, #-4]!
 
                add     pc, pc, ip
@@ -99,17 +95,13 @@ WEAK(memmove)
                W(str)  r4, [r0, #-4]!
                W(str)  r5, [r0, #-4]!
                W(str)  r6, [r0, #-4]!
-               W(str)  r7, [r0, #-4]!
                W(str)  r8, [r0, #-4]!
+               W(str)  r9, [r0, #-4]!
                W(str)  lr, [r0, #-4]!
 
        CALGN(  bcs     2b                      )
 
-7:             ldmfd   sp!, {r5 - r8}
-       UNWIND( .fnend                          ) @ end of second stmfd block
-
-       UNWIND( .fnstart                        )
-       UNWIND( .save   {r0, r4, lr}            ) @ still in first stmfd block
+7:             ldmfd   sp!, {r5, r6, r8, r9}
 
 8:             movs    r2, r2, lsl #31
                ldrbne  r3, [r1, #-1]!
@@ -118,7 +110,7 @@ WEAK(memmove)
                strbne  r3, [r0, #-1]!
                strbcs  r4, [r0, #-1]!
                strbcs  ip, [r0, #-1]
-               ldmfd   sp!, {r0, r4, pc}
+               ldmfd   sp!, {r0, r4, UNWIND(fpreg,) pc}
 
 9:             cmp     ip, #2
                ldrbgt  r3, [r1, #-1]!
@@ -137,13 +129,10 @@ WEAK(memmove)
                ldr     r3, [r1, #0]
                beq     17f
                blt     18f
-       UNWIND( .fnend                          )
 
 
                .macro  backward_copy_shift push pull
 
-       UNWIND( .fnstart                        )
-       UNWIND( .save   {r0, r4, lr}            ) @ still in first stmfd block
                subs    r2, r2, #28
                blt     14f
 
@@ -152,12 +141,7 @@ WEAK(memmove)
        CALGN(  subcc   r2, r2, ip              )
        CALGN(  bcc     15f                     )
 
-11:            stmfd   sp!, {r5 - r9}
-       UNWIND( .fnend                          )
-
-       UNWIND( .fnstart                        )
-       UNWIND( .save   {r0, r4, lr}            )
-       UNWIND( .save   {r5 - r9}               ) @ in new second stmfd block
+11:            stmfd   sp!, {r5, r6, r8 - r10}
 
        PLD(    pld     [r1, #-4]               )
        PLD(    subs    r2, r2, #96             )
@@ -167,35 +151,31 @@ WEAK(memmove)
        PLD(    pld     [r1, #-96]              )
 
 12:    PLD(    pld     [r1, #-128]             )
-13:            ldmdb   r1!, {r7, r8, r9, ip}
+13:            ldmdb   r1!, {r8, r9, r10, ip}
                mov     lr, r3, lspush #\push
                subs    r2, r2, #32
                ldmdb   r1!, {r3, r4, r5, r6}
                orr     lr, lr, ip, lspull #\pull
                mov     ip, ip, lspush #\push
-               orr     ip, ip, r9, lspull #\pull
+               orr     ip, ip, r10, lspull #\pull
+               mov     r10, r10, lspush #\push
+               orr     r10, r10, r9, lspull #\pull
                mov     r9, r9, lspush #\push
                orr     r9, r9, r8, lspull #\pull
                mov     r8, r8, lspush #\push
-               orr     r8, r8, r7, lspull #\pull
-               mov     r7, r7, lspush #\push
-               orr     r7, r7, r6, lspull #\pull
+               orr     r8, r8, r6, lspull #\pull
                mov     r6, r6, lspush #\push
                orr     r6, r6, r5, lspull #\pull
                mov     r5, r5, lspush #\push
                orr     r5, r5, r4, lspull #\pull
                mov     r4, r4, lspush #\push
                orr     r4, r4, r3, lspull #\pull
-               stmdb   r0!, {r4 - r9, ip, lr}
+               stmdb   r0!, {r4 - r6, r8 - r10, ip, lr}
                bge     12b
        PLD(    cmn     r2, #96                 )
        PLD(    bge     13b                     )
 
-               ldmfd   sp!, {r5 - r9}
-       UNWIND( .fnend                          ) @ end of the second stmfd block
-
-       UNWIND( .fnstart                        )
-       UNWIND( .save {r0, r4, lr}              ) @ still in first stmfd block
+               ldmfd   sp!, {r5, r6, r8 - r10}
 
 14:            ands    ip, r2, #28
                beq     16f
@@ -211,7 +191,6 @@ WEAK(memmove)
 
 16:            add     r1, r1, #(\pull / 8)
                b       8b
-       UNWIND( .fnend                          )
 
                .endm
 
@@ -222,5 +201,6 @@ WEAK(memmove)
 
 18:            backward_copy_shift     push=24 pull=8
 
+       UNWIND( .fnend                          )
 ENDPROC(memmove)
 ENDPROC(__memmove)