1/****************************************************************************
2 * Assembly testing and benchmarking tool
3 * Copyright (c) 2015 Martin Storsjo
4 * Copyright (c) 2015 Janne Grunau
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21 *****************************************************************************/
22
23#include "libavutil/arm/asm.S"
24
25/* override fpu so that NEON instructions are rejected */
26#if HAVE_VFP
27FPU     .fpu            vfp
28ELF     .eabi_attribute 10, 0           @ suppress Tag_FP_arch
29#endif
30
31const register_init, align=3
32        .quad 0x21f86d66c8ca00ce
33        .quad 0x75b6ba21077c48ad
34        .quad 0xed56bb2dcb3c7736
35        .quad 0x8bda43d3fd1a7e06
36        .quad 0xb64a9c9e5d318408
37        .quad 0xdf9a54b303f1d3a3
38        .quad 0x4a75479abd64e097
39        .quad 0x249214109d5d1c88
40endconst
41
42const error_message_fpscr
43        .asciz "failed to preserve register FPSCR, changed bits: %x"
44error_message_gpr:
45        .asciz "failed to preserve register r%d"
46error_message_vfp:
47        .asciz "failed to preserve register d%d"
48error_message_stack:
49        .asciz "failed to preserve stack"
50endconst
51
52@ max number of args used by any asm function.
53#define MAX_ARGS 15
54
55#define ARG_STACK 4*(MAX_ARGS - 4)
56
57@ Align the used stack space to 8 to preserve the stack alignment.
58@ +8 for stack canary reference.
59#define ARG_STACK_A (((ARG_STACK + pushed + 7) & ~7) - pushed + 8)
60
61.macro clobbercheck variant
62.equ pushed, 4*9
63function checkasm_checked_call_\variant, export=1
64        push            {r4-r11, lr}
65.ifc \variant, vfp
66        vpush           {d8-d15}
67        fmrx            r4,  FPSCR
68        push            {r4}
69.equ pushed, pushed + 16*4 + 4
70.endif
71
72        movrel          r12, register_init
73.ifc \variant, vfp
74        vldm            r12, {d8-d15}
75.endif
76        ldm             r12, {r4-r11}
77
78        sub             sp,  sp,  #ARG_STACK_A
79.equ pos, 0
80.rept MAX_ARGS-4
81        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + pos]
82        str             r12, [sp, #pos]
83.equ pos, pos + 4
84.endr
85
86        @ For stack overflows, the callee is free to overwrite the parameters
87        @ that were passed on the stack (if any), so we can only check after
88        @ that point. First figure out how many parameters the function
89        @ really took on the stack:
90        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
91        @ Load the first non-parameter value from the stack, that should be
92        @ left untouched by the function. Store a copy of it inverted, so that
93        @ e.g. overwriting everything with zero would be noticed.
94        ldr             r12, [sp, r12, lsl #2]
95        mvn             r12, r12
96        str             r12, [sp, #ARG_STACK_A - 4]
97
98        mov             r12, r0
99        mov             r0,  r2
100        mov             r1,  r3
101        ldrd            r2,  r3,  [sp, #ARG_STACK_A + pushed]
102        @ Call the target function
103        blx             r12
104
105        @ Load the number of stack parameters, stack canary and its reference
106        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
107        ldr             r2,  [sp, r12, lsl #2]
108        ldr             r3,  [sp, #ARG_STACK_A - 4]
109
110        add             sp,  sp,  #ARG_STACK_A
111        push            {r0, r1}
112
113        mvn             r3,  r3
114        cmp             r2,  r3
115        bne             5f
116
117        movrel          r12, register_init
118.ifc \variant, vfp
119.macro check_reg_vfp, dreg, offset
120        ldrd            r2,  r3,  [r12, #8 * (\offset)]
121        vmov            r0,  lr,  \dreg
122        eor             r2,  r2,  r0
123        eor             r3,  r3,  lr
124        orrs            r2,  r2,  r3
125        bne             4f
126.endm
127
128.irp n, 8, 9, 10, 11, 12, 13, 14, 15
129        @ keep track of the checked double/SIMD register
130        mov             r1,  #\n
131        check_reg_vfp   d\n, \n-8
132.endr
133.purgem check_reg_vfp
134
135        fmrx            r1,  FPSCR
136        ldr             r3,  [sp, #8]
137        eor             r1,  r1,  r3
138        @ Ignore changes in bits 0-4 and 7
139        bic             r1,  r1,  #0x9f
140        @ Ignore changes in the topmost 5 bits
141        bics            r1,  r1,  #0xf8000000
142        bne             3f
143.endif
144
145        @ keep track of the checked GPR
146        mov             r1,  #4
147.macro check_reg reg1, reg2=
148        ldrd            r2,  r3,  [r12], #8
149        eors            r2,  r2,  \reg1
150        bne             2f
151        add             r1,  r1,  #1
152.ifnb \reg2
153        eors            r3,  r3,  \reg2
154        bne             2f
155.endif
156        add             r1,  r1,  #1
157.endm
158        check_reg       r4,  r5
159        check_reg       r6,  r7
160@ r9 is a volatile register in the ios ABI
161#ifdef __APPLE__
162        check_reg       r8
163#else
164        check_reg       r8,  r9
165#endif
166        check_reg       r10, r11
167.purgem check_reg
168
169        b               0f
1705:
171        movrel          r0, error_message_stack
172        b               1f
1734:
174        movrel          r0, error_message_vfp
175        b               1f
1763:
177        movrel          r0, error_message_fpscr
178        b               1f
1792:
180        movrel          r0, error_message_gpr
1811:
182        bl              X(checkasm_fail_func)
1830:
184        pop             {r0, r1}
185.ifc \variant, vfp
186        pop             {r2}
187        fmxr            FPSCR, r2
188        vpop            {d8-d15}
189.endif
190        pop             {r4-r11, pc}
191endfunc
192.endm
193
194#if HAVE_VFP || HAVE_NEON
195clobbercheck vfp
196#endif
197clobbercheck novfp
198