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/aarch64/asm.S"
24 
25 const register_init, align=4
26         .quad 0x21f86d66c8ca00ce
27         .quad 0x75b6ba21077c48ad
28         .quad 0xed56bb2dcb3c7736
29         .quad 0x8bda43d3fd1a7e06
30         .quad 0xb64a9c9e5d318408
31         .quad 0xdf9a54b303f1d3a3
32         .quad 0x4a75479abd64e097
33         .quad 0x249214109d5d1c88
34         .quad 0x1a1b2550a612b48c
35         .quad 0x79445c159ce79064
36         .quad 0x2eed899d5a28ddcd
37         .quad 0x86b2536fcd8cf636
38         .quad 0xb0856806085e7943
39         .quad 0x3f2bf84fc0fcca4e
40         .quad 0xacbd382dcf5b8de2
41         .quad 0xd229e1f5b281303f
42         .quad 0x71aeaff20b095fd9
43         .quad 0xab63e2e11fa38ed9
44 endconst
45 
46 
47 const error_message_register
48         .asciz "failed to preserve register"
49 error_message_stack:
50         .asciz "stack clobbered"
51 endconst
52 
53 
54 // max number of args used by any asm function.
55 #define MAX_ARGS 15
56 
57 #define CLOBBER_STACK ((8*MAX_ARGS + 15) & ~15)
58 
59 function checkasm_stack_clobber, export=1
60         mov             x3,  sp
61         mov             x2,  #CLOBBER_STACK
62 1:
63         stp             x0,  x1,  [sp, #-16]!
64         subs            x2,  x2,  #16
65         b.gt            1b
66         mov             sp,  x3
67         ret
68 endfunc
69 
70 // + 16 for stack canary reference
71 #define ARG_STACK ((8*(MAX_ARGS - 8) + 15) & ~15 + 16)
72 
73 function checkasm_checked_call, export=1
74         stp             x29, x30, [sp, #-16]!
75         mov             x29, sp
76         stp             x19, x20, [sp, #-16]!
77         stp             x21, x22, [sp, #-16]!
78         stp             x23, x24, [sp, #-16]!
79         stp             x25, x26, [sp, #-16]!
80         stp             x27, x28, [sp, #-16]!
81         stp             d8,  d9,  [sp, #-16]!
82         stp             d10, d11, [sp, #-16]!
83         stp             d12, d13, [sp, #-16]!
84         stp             d14, d15, [sp, #-16]!
85 
86         movrel          x9, register_init
87         ldp             d8,  d9,  [x9], #16
88         ldp             d10, d11, [x9], #16
89         ldp             d12, d13, [x9], #16
90         ldp             d14, d15, [x9], #16
91         ldp             x19, x20, [x9], #16
92         ldp             x21, x22, [x9], #16
93         ldp             x23, x24, [x9], #16
94         ldp             x25, x26, [x9], #16
95         ldp             x27, x28, [x9], #16
96 
97         sub             sp,  sp,  #ARG_STACK
98 .equ pos, 0
99 .rept MAX_ARGS-8
100         // Skip the first 8 args, that are loaded into registers
101         ldr             x9, [x29, #16 + 8*8 + pos]
102         str             x9, [sp, #pos]
103 .equ pos, pos + 8
104 .endr
105 
106         // Fill x8-x17 with garbage. This doesn't have to be preserved,
107         // but avoids relying on them having any particular value.
108         movrel          x9, register_init
109         ldp             x10, x11, [x9], #32
110         ldp             x12, x13, [x9], #32
111         ldp             x14, x15, [x9], #32
112         ldp             x16, x17, [x9], #32
113         ldp             x8,  x9,  [x9]
114 
115         // For stack overflows, the callee is free to overwrite the parameters
116         // that were passed on the stack (if any), so we can only check after
117         // that point. First figure out how many parameters the function
118         // really took on the stack:
119         ldr             w2,  [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
120         // Load the first non-parameter value from the stack, that should be
121         // left untouched by the function. Store a copy of it inverted, so that
122         // e.g. overwriting everything with zero would be noticed.
123         ldr             x2,  [sp, x2, lsl #3]
124         mvn             x2,  x2
125         str             x2,  [sp, #ARG_STACK-8]
126 
127         // Load the in-register arguments
128         mov             x12, x0
129         ldp             x0,  x1,  [x29, #16]
130         ldp             x2,  x3,  [x29, #32]
131         ldp             x4,  x5,  [x29, #48]
132         ldp             x6,  x7,  [x29, #64]
133         // Call the target function
134         blr             x12
135 
136         // Load the number of stack parameters, stack canary and its reference
137         ldr             w2,  [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
138         ldr             x2,  [sp, x2, lsl #3]
139         ldr             x3,  [sp, #ARG_STACK-8]
140 
141         add             sp,  sp,  #ARG_STACK
142         stp             x0,  x1,  [sp, #-16]!
143 
144         mvn             x3,  x3
145         cmp             x2,  x3
146         b.ne            2f
147 
148         movrel          x9, register_init
149         movi            v3.8h,  #0
150 
151 .macro check_reg_neon reg1, reg2
152         ldr             q1,  [x9], #16
153         uzp1            v2.2d,  v\reg1\().2d, v\reg2\().2d
154         eor             v1.16b, v1.16b, v2.16b
155         orr             v3.16b, v3.16b, v1.16b
156 .endm
157         check_reg_neon  8,  9
158         check_reg_neon  10, 11
159         check_reg_neon  12, 13
160         check_reg_neon  14, 15
161         uqxtn           v3.8b,  v3.8h
162         umov            x3,  v3.d[0]
163 
164 .macro check_reg reg1, reg2
165         ldp             x0,  x1,  [x9], #16
166         eor             x0,  x0,  \reg1
167         eor             x1,  x1,  \reg2
168         orr             x3,  x3,  x0
169         orr             x3,  x3,  x1
170 .endm
171         check_reg       x19, x20
172         check_reg       x21, x22
173         check_reg       x23, x24
174         check_reg       x25, x26
175         check_reg       x27, x28
176 
177         cbz             x3,  0f
178 
179         movrel          x0, error_message_register
180         b               1f
181 2:
182         movrel          x0, error_message_stack
183 1:
184         bl              X(checkasm_fail_func)
185 0:
186         ldp             x0,  x1,  [sp], #16
187         ldp             d14, d15, [sp], #16
188         ldp             d12, d13, [sp], #16
189         ldp             d10, d11, [sp], #16
190         ldp             d8,  d9,  [sp], #16
191         ldp             x27, x28, [sp], #16
192         ldp             x25, x26, [sp], #16
193         ldp             x23, x24, [sp], #16
194         ldp             x21, x22, [sp], #16
195         ldp             x19, x20, [sp], #16
196         ldp             x29, x30, [sp], #16
197         ret
198 endfunc
199