2017-02-16 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libffi / src / arm / sysv.S
blobfd165890e02cbe73da7915419b0edc268abe543f
1 /* -----------------------------------------------------------------------
2    sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
3             Copyright (c) 2011 Plausible Labs Cooperative, Inc.
5    ARM Foreign Function Interface
7    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the
9    ``Software''), to deal in the Software without restriction, including
10    without limitation the rights to use, copy, modify, merge, publish,
11    distribute, sublicense, and/or sell copies of the Software, and to
12    permit persons to whom the Software is furnished to do so, subject to
13    the following conditions:
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
18    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25    DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
28 #define LIBFFI_ASM      
29 #include <fficonfig.h>
30 #include <ffi.h>
31 #include <ffi_cfi.h>
32 #include "internal.h"
34 /* GCC 4.8 provides __ARM_ARCH; construct it otherwise.  */
35 #ifndef __ARM_ARCH
36 # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
37      || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
38      || defined(__ARM_ARCH_7EM__)
39 #  define __ARM_ARCH 7
40 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
41         || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
42         || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
43         || defined(__ARM_ARCH_6M__)
44 #  define __ARM_ARCH 6
45 # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
46         || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
47         || defined(__ARM_ARCH_5TEJ__)
48 #  define __ARM_ARCH 5
49 # else
50 #  define __ARM_ARCH 4
51 # endif
52 #endif
54 /* Conditionally compile unwinder directives.  */
55 .macro UNWIND text:vararg
56 #ifdef __ARM_EABI__
57         \text
58 #endif  
59 .endm
60 #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
61         .cfi_sections   .debug_frame
62 #endif
64 #define CONCAT(a, b)    CONCAT2(a, b)
65 #define CONCAT2(a, b)   a ## b
67 #ifdef __USER_LABEL_PREFIX__
68 # define CNAME(X)       CONCAT (__USER_LABEL_PREFIX__, X)
69 #else
70 # define CNAME(X)       X
71 #endif
72 #ifdef __ELF__
73 # define SIZE(X)        .size CNAME(X), . - CNAME(X)
74 # define TYPE(X, Y)     .type CNAME(X), Y
75 #else
76 # define SIZE(X)
77 # define TYPE(X, Y)
78 #endif
80 #define ARM_FUNC_START(name, gl) \
81         .align  3; \
82         .ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
83         TYPE(name, %function); \
84         CNAME(name):
86 #define ARM_FUNC_END(name) \
87         SIZE(name)
89 /* Aid in defining a jump table with 8 bytes between entries.  */
90 .macro E index
91         .if . - 0b - 8*\index
92         .error "type table out of sync"
93         .endif
94 .endm
96         .text
97         .syntax unified
98         .arm
100         /* We require interworking on LDM, which implies ARMv5T,
101            which implies the existance of BLX.  */
102         .arch   armv5t
104         /* Note that we use STC and LDC to encode VFP instructions,
105            so that we do not need ".fpu vfp", nor get that added to
106            the object file attributes.  These will not be executed
107            unless the FFI_VFP abi is used.  */
109         @ r0:   stack
110         @ r1:   frame
111         @ r2:   fn
112         @ r3:   vfp_used
114 ARM_FUNC_START(ffi_call_VFP, 1)
115         UNWIND  .fnstart
116         cfi_startproc
118         cmp     r3, #3                  @ load only d0 if possible
119         ldcle   p11, cr0, [r0]          @ vldrle d0, [sp]
120         ldcgt   p11, cr0, [r0], {16}    @ vldmgt sp, {d0-d7}
121         add     r0, r0, #64             @ discard the vfp register args
122         /* FALLTHRU */
123 ARM_FUNC_END(ffi_call_VFP)
125 ARM_FUNC_START(ffi_call_SYSV, 1)
126         stm     r1, {fp, lr}
127         mov     fp, r1
129         @ This is a bit of a lie wrt the origin of the unwind info, but
130         @ now we've got the usual frame pointer and two saved registers.
131         UNWIND  .save {fp,lr}
132         UNWIND  .setfp fp, sp
133         cfi_def_cfa(fp, 8)
134         cfi_rel_offset(fp, 0)
135         cfi_rel_offset(lr, 4)
137         mov     sp, r0          @ install the stack pointer
138         mov     lr, r2          @ move the fn pointer out of the way
139         ldr     ip, [fp, #16]   @ install the static chain
140         ldmia   sp!, {r0-r3}    @ move first 4 parameters in registers.
141         blx     lr              @ call fn
143         @ Load r2 with the pointer to storage for the return value
144         @ Load r3 with the return type code
145         ldr     r2, [fp, #8]
146         ldr     r3, [fp, #12]
148         @ Deallocate the stack with the arguments.
149         mov     sp, fp
150         cfi_def_cfa_register(sp)
152         @ Store values stored in registers.
153         .align  3
154         add     pc, pc, r3, lsl #3
155         nop
157 E ARM_TYPE_VFP_S
158         stc     p10, cr0, [r2]          @ vstr s0, [r2]
159         pop     {fp,pc}
160 E ARM_TYPE_VFP_D
161         stc     p11, cr0, [r2]          @ vstr d0, [r2]
162         pop     {fp,pc}
163 E ARM_TYPE_VFP_N
164         stc     p11, cr0, [r2], {8}     @ vstm r2, {d0-d3}
165         pop     {fp,pc}
166 E ARM_TYPE_INT64
167         str     r1, [r2, #4]
168         nop
169 E ARM_TYPE_INT
170         str     r0, [r2]
171         pop     {fp,pc}
172 E ARM_TYPE_VOID
173         pop     {fp,pc}
174         nop
175 E ARM_TYPE_STRUCT
176         pop     {fp,pc}
178         cfi_endproc
179         UNWIND  .fnend
180 ARM_FUNC_END(ffi_call_SYSV)
184         int ffi_closure_inner_* (cif, fun, user_data, frame)
187 ARM_FUNC_START(ffi_go_closure_SYSV, 1)
188         cfi_startproc
189         stmdb   sp!, {r0-r3}                    @ save argument regs
190         cfi_adjust_cfa_offset(16)
191         ldr     r0, [ip, #4]                    @ load cif
192         ldr     r1, [ip, #8]                    @ load fun
193         mov     r2, ip                          @ load user_data
194         b       0f
195         cfi_endproc
196 ARM_FUNC_END(ffi_go_closure_SYSV)
198 ARM_FUNC_START(ffi_closure_SYSV, 1)
199         UNWIND  .fnstart
200         cfi_startproc
201         stmdb   sp!, {r0-r3}                    @ save argument regs
202         cfi_adjust_cfa_offset(16)
203         ldr     r0, [ip, #FFI_TRAMPOLINE_SIZE]    @ load cif
204         ldr     r1, [ip, #FFI_TRAMPOLINE_SIZE+4]  @ load fun
205         ldr     r2, [ip, #FFI_TRAMPOLINE_SIZE+8]  @ load user_data
207         add     ip, sp, #16                     @ compute entry sp
208         sub     sp, sp, #64+32                  @ allocate frame
209         cfi_adjust_cfa_offset(64+32)
210         stmdb   sp!, {ip,lr}
212         /* Remember that EABI unwind info only applies at call sites.
213            We need do nothing except note the save of the stack pointer
214            and the link registers.  */
215         UNWIND  .save {sp,lr}
216         cfi_adjust_cfa_offset(8)
217         cfi_rel_offset(lr, 4)
219         add     r3, sp, #8                      @ load frame
220         bl      CNAME(ffi_closure_inner_SYSV)
222         @ Load values returned in registers.
223         add     r2, sp, #8+64                   @ load result
224         adr     r3, CNAME(ffi_closure_ret)
225         add     pc, r3, r0, lsl #3
226         cfi_endproc
227         UNWIND  .fnend
228 ARM_FUNC_END(ffi_closure_SYSV)
230 ARM_FUNC_START(ffi_go_closure_VFP, 1)
231         cfi_startproc
232         stmdb   sp!, {r0-r3}                    @ save argument regs
233         cfi_adjust_cfa_offset(16)
234         ldr     r0, [ip, #4]                    @ load cif
235         ldr     r1, [ip, #8]                    @ load fun
236         mov     r2, ip                          @ load user_data
237         b       0f
238         cfi_endproc
239 ARM_FUNC_END(ffi_go_closure_VFP)
241 ARM_FUNC_START(ffi_closure_VFP, 1)
242         UNWIND  .fnstart
243         cfi_startproc
244         stmdb   sp!, {r0-r3}                    @ save argument regs
245         cfi_adjust_cfa_offset(16)
246         ldr     r0, [ip, #FFI_TRAMPOLINE_SIZE]    @ load cif
247         ldr     r1, [ip, #FFI_TRAMPOLINE_SIZE+4]  @ load fun
248         ldr     r2, [ip, #FFI_TRAMPOLINE_SIZE+8]  @ load user_data
250         add     ip, sp, #16
251         sub     sp, sp, #64+32                  @ allocate frame
252         cfi_adjust_cfa_offset(64+32)
253         stc     p11, cr0, [sp], {16}            @ vstm sp, {d0-d7}
254         stmdb   sp!, {ip,lr}
256         /* See above.  */
257         UNWIND  .save {sp,lr}
258         cfi_adjust_cfa_offset(8)
259         cfi_rel_offset(lr, 4)
261         add     r3, sp, #8                      @ load frame
262         bl      CNAME(ffi_closure_inner_VFP)
264         @ Load values returned in registers.
265         add     r2, sp, #8+64                   @ load result
266         adr     r3, CNAME(ffi_closure_ret)
267         add     pc, r3, r0, lsl #3
268         cfi_endproc
269         UNWIND  .fnend
270 ARM_FUNC_END(ffi_closure_VFP)
272 /* Load values returned in registers for both closure entry points.
273    Note that we use LDM with SP in the register set.  This is deprecated
274    by ARM, but not yet unpredictable.  */
276 ARM_FUNC_START(ffi_closure_ret, 0)
277         cfi_startproc
278         cfi_rel_offset(sp, 0)
279         cfi_rel_offset(lr, 4)
281 E ARM_TYPE_VFP_S
282         ldc     p10, cr0, [r2]                  @ vldr s0, [r2]
283         ldm     sp, {sp,pc}
284 E ARM_TYPE_VFP_D
285         ldc     p11, cr0, [r2]                  @ vldr d0, [r2]
286         ldm     sp, {sp,pc}
287 E ARM_TYPE_VFP_N
288         ldc     p11, cr0, [r2], {8}             @ vldm r2, {d0-d3}
289         ldm     sp, {sp,pc}
290 E ARM_TYPE_INT64
291         ldr     r1, [r2, #4]
292         nop
293 E ARM_TYPE_INT
294         ldr     r0, [r2]
295         ldm     sp, {sp,pc}
296 E ARM_TYPE_VOID
297         ldm     sp, {sp,pc}
298         nop
299 E ARM_TYPE_STRUCT
300         ldm     sp, {sp,pc}
301         cfi_endproc
302 ARM_FUNC_END(ffi_closure_ret)
304 #if FFI_EXEC_TRAMPOLINE_TABLE
306 /* ??? The iOS support should be updated.  The first insn used to
307    be STMFD, but that's been moved into ffi_closure_SYSV.  If the
308    writable page is put after this one we can make use of the
309    pc+8 feature of the architecture.  We can also reduce the size
310    of the thunk to 8 and pack more of these into the page.
312    In the meantime, simply replace the STMFD with a NOP so as to
313    keep all the magic numbers the same within ffi.c.  */
315         .align  12
316 ARM_FUNC_START(ffi_closure_trampoline_table_page)
317 .rept   4096 / 12
318         nop
319         ldr     ip, [pc, #-4092]
320         ldr     pc, [pc, #-4092]
321 .endr
323 #else
325 ARM_FUNC_START(ffi_arm_trampoline, 1)
326 0:      adr     ip, 0b
327         ldr     pc, 1f
328 1:      .long   0
329 ARM_FUNC_END(ffi_arm_trampoline)
331 #endif /* FFI_EXEC_TRAMPOLINE_TABLE */
333 #if defined __ELF__ && defined __linux__
334         .section        .note.GNU-stack,"",%progbits
335 #endif