Fortran: Suppress wrong End Of File error with user defined IO.
[official-gcc.git] / libffi / src / arm / sysv.S
blobfb36213c6805fa5017154328e094daeaf902a0c5
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 #ifdef __arm__
29 #define LIBFFI_ASM
30 #include <fficonfig.h>
31 #include <ffi.h>
32 #include <ffi_cfi.h>
33 #include "internal.h"
35 /* GCC 4.8 provides __ARM_ARCH; construct it otherwise.  */
36 #ifndef __ARM_ARCH
37 # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
38      || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
39      || defined(__ARM_ARCH_7EM__)
40 #  define __ARM_ARCH 7
41 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
42         || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
43         || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
44         || defined(__ARM_ARCH_6M__)
45 #  define __ARM_ARCH 6
46 # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
47         || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
48         || defined(__ARM_ARCH_5TEJ__)
49 #  define __ARM_ARCH 5
50 # else
51 #  define __ARM_ARCH 4
52 # endif
53 #endif
55 /* Conditionally compile unwinder directives.  */
56 #ifdef __ARM_EABI__
57 # define UNWIND(...)    __VA_ARGS__
58 #else
59 # define UNWIND(...)
60 #endif
62 #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
63         .cfi_sections   .debug_frame
64 #endif
66 #define CONCAT(a, b)    CONCAT2(a, b)
67 #define CONCAT2(a, b)   a ## b
69 #ifdef __USER_LABEL_PREFIX__
70 # define CNAME(X)       CONCAT (__USER_LABEL_PREFIX__, X)
71 #else
72 # define CNAME(X)       X
73 #endif
74 #ifdef __ELF__
75 # define SIZE(X)        .size CNAME(X), . - CNAME(X)
76 # define TYPE(X, Y)     .type CNAME(X), Y
77 #else
78 # define SIZE(X)
79 # define TYPE(X, Y)
80 #endif
82 #define ARM_FUNC_START_LOCAL(name)      \
83         .align  3;                      \
84         TYPE(CNAME(name), %function);   \
85         CNAME(name):
87 #define ARM_FUNC_START(name)            \
88         .globl CNAME(name);             \
89         FFI_HIDDEN(CNAME(name));        \
90         ARM_FUNC_START_LOCAL(name)
92 #define ARM_FUNC_END(name) \
93         SIZE(name)
95         .text
96         .syntax unified
97 #if defined(_WIN32)
98         /* Windows on ARM is thumb-only */
99         .thumb
100 #else
101         /* Keep the assembly in ARM mode in other cases, for simplicity
102          * (to avoid interworking issues). */
103 #undef __thumb__
104         .arm
105 #endif
107 /* Aid in defining a jump table with 8 bytes between entries.  */
108 #ifdef __thumb__
109 /* In thumb mode, instructions can be shorter than expected in arm mode, so
110  * we need to align the start of each case. */
111 # define E(index) .align 3
112 #elif defined(__clang__)
113 /* ??? The clang assembler doesn't handle .if with symbolic expressions.  */
114 # define E(index)
115 #else
116 # define E(index)                               \
117         .if . - 0b - 8*index;                   \
118         .error "type table out of sync";        \
119         .endif
120 #endif
123 #ifndef __clang__
124         /* We require interworking on LDM, which implies ARMv5T,
125            which implies the existance of BLX.  */
126         .arch   armv5t
127 #endif
129         /* Note that we use STC and LDC to encode VFP instructions,
130            so that we do not need ".fpu vfp", nor get that added to
131            the object file attributes.  These will not be executed
132            unless the FFI_VFP abi is used.  */
134         @ r0:   stack
135         @ r1:   frame
136         @ r2:   fn
137         @ r3:   vfp_used
139 ARM_FUNC_START(ffi_call_VFP)
140         UNWIND(.fnstart)
141         cfi_startproc
143         cmp     r3, #3                  @ load only d0 if possible
144         ite     le
145 #ifdef __clang__
146         vldrle d0, [r0]
147         vldmgt r0, {d0-d7}
148 #else
149         ldcle   p11, cr0, [r0]          @ vldrle d0, [r0]
150         ldcgt   p11, cr0, [r0], {16}    @ vldmgt r0, {d0-d7}
151 #endif
152         add     r0, r0, #64             @ discard the vfp register args
153         /* FALLTHRU */
154 ARM_FUNC_END(ffi_call_VFP)
156 ARM_FUNC_START(ffi_call_SYSV)
157         stm     r1, {fp, lr}
158         mov     fp, r1
160         @ This is a bit of a lie wrt the origin of the unwind info, but
161         @ now we've got the usual frame pointer and two saved registers.
162         UNWIND(.save {fp,lr})
163         UNWIND(.setfp fp, sp)
164         cfi_def_cfa(fp, 8)
165         cfi_rel_offset(fp, 0)
166         cfi_rel_offset(lr, 4)
168         mov     sp, r0          @ install the stack pointer
169         mov     lr, r2          @ move the fn pointer out of the way
170         ldr     ip, [fp, #16]   @ install the static chain
171         ldmia   sp!, {r0-r3}    @ move first 4 parameters in registers.
172         blx     lr              @ call fn
174         @ Load r2 with the pointer to storage for the return value
175         @ Load r3 with the return type code
176         ldr     r2, [fp, #8]
177         ldr     r3, [fp, #12]
179         @ Deallocate the stack with the arguments.
180         mov     sp, fp
181         cfi_def_cfa_register(sp)
183         @ Store values stored in registers.
184 #ifndef __thumb__
185         .align  3
186         add     pc, pc, r3, lsl #3
187         nop
188 #else
189         adr     ip, 0f
190         add     ip, ip, r3, lsl #3
191         mov     pc, ip
192         .align  3
193 #endif
195 E(ARM_TYPE_VFP_S)
196 #ifdef __clang__
197         vstr s0, [r2]
198 #else
199         stc     p10, cr0, [r2]          @ vstr s0, [r2]
200 #endif
201         pop     {fp,pc}
202 E(ARM_TYPE_VFP_D)
203 #ifdef __clang__
204         vstr d0, [r2]
205 #else
206         stc     p11, cr0, [r2]          @ vstr d0, [r2]
207 #endif
208         pop     {fp,pc}
209 E(ARM_TYPE_VFP_N)
210 #ifdef __clang__
211         vstm r2, {d0-d3}
212 #else
213         stc     p11, cr0, [r2], {8}     @ vstm r2, {d0-d3}
214 #endif
215         pop     {fp,pc}
216 E(ARM_TYPE_INT64)
217         str     r1, [r2, #4]
218         nop
219 E(ARM_TYPE_INT)
220         str     r0, [r2]
221         pop     {fp,pc}
222 E(ARM_TYPE_VOID)
223         pop     {fp,pc}
224         nop
225 E(ARM_TYPE_STRUCT)
226         pop     {fp,pc}
228         cfi_endproc
229         UNWIND(.fnend)
230 ARM_FUNC_END(ffi_call_SYSV)
232 #if FFI_CLOSURES
235         int ffi_closure_inner_* (cif, fun, user_data, frame)
238 ARM_FUNC_START(ffi_go_closure_SYSV)
239         cfi_startproc
240         stmdb   sp!, {r0-r3}                    @ save argument regs
241         cfi_adjust_cfa_offset(16)
242         ldr     r0, [ip, #4]                    @ load cif
243         ldr     r1, [ip, #8]                    @ load fun
244         mov     r2, ip                          @ load user_data
245         b       0f
246         cfi_endproc
247 ARM_FUNC_END(ffi_go_closure_SYSV)
249 ARM_FUNC_START(ffi_closure_SYSV)
250         UNWIND(.fnstart)
251         cfi_startproc
252 #ifdef _WIN32
253         ldmfd   sp!, {r0, ip}                   @ restore fp (r0 is used for stack alignment)
254 #endif
255         stmdb   sp!, {r0-r3}                    @ save argument regs
256         cfi_adjust_cfa_offset(16)
258 #if FFI_EXEC_TRAMPOLINE_TABLE
259         ldr ip, [ip]                            @ ip points to the config page, dereference to get the ffi_closure*
260 #endif
261         ldr     r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET]        @ load cif
262         ldr     r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4]  @ load fun
263         ldr     r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8]  @ load user_data
265         add     ip, sp, #16                     @ compute entry sp
266         sub     sp, sp, #64+32                  @ allocate frame
267         cfi_adjust_cfa_offset(64+32)
268         stmdb   sp!, {ip,lr}
270         /* Remember that EABI unwind info only applies at call sites.
271            We need do nothing except note the save of the stack pointer
272            and the link registers.  */
273         UNWIND(.save {sp,lr})
274         cfi_adjust_cfa_offset(8)
275         cfi_rel_offset(lr, 4)
277         add     r3, sp, #8                      @ load frame
278         bl      CNAME(ffi_closure_inner_SYSV)
280         @ Load values returned in registers.
281         add     r2, sp, #8+64                   @ load result
282         adr     r3, CNAME(ffi_closure_ret)
283 #ifndef __thumb__
284         add     pc, r3, r0, lsl #3
285 #else
286         add     r3, r3, r0, lsl #3
287         mov     pc, r3
288 #endif
289         cfi_endproc
290         UNWIND(.fnend)
291 ARM_FUNC_END(ffi_closure_SYSV)
293 ARM_FUNC_START(ffi_go_closure_VFP)
294         cfi_startproc
295         stmdb   sp!, {r0-r3}                    @ save argument regs
296         cfi_adjust_cfa_offset(16)
297         ldr     r0, [ip, #4]                    @ load cif
298         ldr     r1, [ip, #8]                    @ load fun
299         mov     r2, ip                          @ load user_data
300         b       0f
301         cfi_endproc
302 ARM_FUNC_END(ffi_go_closure_VFP)
304 ARM_FUNC_START(ffi_closure_VFP)
305         UNWIND(.fnstart)
306         cfi_startproc
307 #ifdef _WIN32
308         ldmfd   sp!, {r0, ip}                   @ restore fp (r0 is used for stack alignment)
309 #endif
310         stmdb   sp!, {r0-r3}                    @ save argument regs
311         cfi_adjust_cfa_offset(16)
313 #if FFI_EXEC_TRAMPOLINE_TABLE
314         ldr ip, [ip]                            @ ip points to the config page, dereference to get the ffi_closure*
315 #endif
316         ldr     r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET]        @ load cif
317         ldr     r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4]  @ load fun
318         ldr     r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8]  @ load user_data
320         add     ip, sp, #16
321         sub     sp, sp, #64+32                  @ allocate frame
322         cfi_adjust_cfa_offset(64+32)
323 #ifdef __clang__
324         vstm sp, {d0-d7}
325 #else
326         stc     p11, cr0, [sp], {16}            @ vstm sp, {d0-d7}
327 #endif
328         stmdb   sp!, {ip,lr}
330         /* See above.  */
331         UNWIND(.save {sp,lr})
332         cfi_adjust_cfa_offset(8)
333         cfi_rel_offset(lr, 4)
335         add     r3, sp, #8                      @ load frame
336         bl      CNAME(ffi_closure_inner_VFP)
338         @ Load values returned in registers.
339         add     r2, sp, #8+64                   @ load result
340         adr     r3, CNAME(ffi_closure_ret)
341 #ifndef __thumb__
342         add     pc, r3, r0, lsl #3
343 #else
344         add     r3, r3, r0, lsl #3
345         mov     pc, r3
346 #endif
347         cfi_endproc
348         UNWIND(.fnend)
349 ARM_FUNC_END(ffi_closure_VFP)
351 /* Load values returned in registers for both closure entry points.
352    Note that we use LDM with SP in the register set.  This is deprecated
353    by ARM, but not yet unpredictable.  */
355 ARM_FUNC_START_LOCAL(ffi_closure_ret)
356         cfi_startproc
357         cfi_rel_offset(sp, 0)
358         cfi_rel_offset(lr, 4)
360 E(ARM_TYPE_VFP_S)
361 #ifdef __clang__
362         vldr s0, [r2]
363 #else
364         ldc     p10, cr0, [r2]                  @ vldr s0, [r2]
365 #endif
366         b       call_epilogue
367 E(ARM_TYPE_VFP_D)
368 #ifdef __clang__
369         vldr d0, [r2]
370 #else
371         ldc     p11, cr0, [r2]                  @ vldr d0, [r2]
372 #endif
373         b       call_epilogue
374 E(ARM_TYPE_VFP_N)
375 #ifdef __clang__
376         vldm r2, {d0-d3}
377 #else
378         ldc     p11, cr0, [r2], {8}             @ vldm r2, {d0-d3}
379 #endif
380         b       call_epilogue
381 E(ARM_TYPE_INT64)
382         ldr     r1, [r2, #4]
383         nop
384 E(ARM_TYPE_INT)
385         ldr     r0, [r2]
386         b       call_epilogue
387 E(ARM_TYPE_VOID)
388         b       call_epilogue
389         nop
390 E(ARM_TYPE_STRUCT)
391         b       call_epilogue
392 call_epilogue:
393 #ifndef __thumb__
394         ldm     sp, {sp,pc}
395 #else
396         ldm     sp, {ip,lr}
397         mov     sp, ip
398         bx      lr
399 #endif
400         cfi_endproc
401 ARM_FUNC_END(ffi_closure_ret)
403 #if defined(FFI_EXEC_STATIC_TRAMP)
404 ARM_FUNC_START(ffi_closure_SYSV_alt)
405         /* See the comments above trampoline_code_table. */
406         ldr     ip, [sp, #4]                    /* Load closure in ip */
407         add     sp, sp, 8                       /* Restore the stack */
408         b       CNAME(ffi_closure_SYSV)
409 ARM_FUNC_END(ffi_closure_SYSV_alt)
411 ARM_FUNC_START(ffi_closure_VFP_alt)
412         /* See the comments above trampoline_code_table. */
413         ldr     ip, [sp, #4]                    /* Load closure in ip */
414         add     sp, sp, 8                       /* Restore the stack */
415         b       CNAME(ffi_closure_VFP)
416 ARM_FUNC_END(ffi_closure_VFP_alt)
419  * Below is the definition of the trampoline code table. Each element in
420  * the code table is a trampoline.
421  */
423  * The trampoline uses register ip (r12). It saves the original value of ip
424  * on the stack.
426  * The trampoline has two parameters - target code to jump to and data for
427  * the target code. The trampoline extracts the parameters from its parameter
428  * block (see tramp_table_map()). The trampoline saves the data address on
429  * the stack. Finally, it jumps to the target code.
431  * The target code can choose to:
433  * - restore the value of ip
434  * - load the data address in a register
435  * - restore the stack pointer to what it was when the trampoline was invoked.
436  */
437         .align  ARM_TRAMP_MAP_SHIFT
438 ARM_FUNC_START(trampoline_code_table)
439         .rept   ARM_TRAMP_MAP_SIZE / ARM_TRAMP_SIZE
440         sub     sp, sp, #8              /* Make space on the stack */
441         str     ip, [sp]                /* Save ip on stack */
442         ldr     ip, [pc, #4080]         /* Copy data into ip */
443         str     ip, [sp, #4]            /* Save data on stack */
444         ldr     pc, [pc, #4076]         /* Copy code into PC */
445         .endr
446 ARM_FUNC_END(trampoline_code_table)
447         .align  ARM_TRAMP_MAP_SHIFT
448 #endif /* FFI_EXEC_STATIC_TRAMP */
450 #endif /* FFI_CLOSURES */
452 #if FFI_EXEC_TRAMPOLINE_TABLE
454 #ifdef __MACH__
455 #include <mach/machine/vm_param.h>
457 .align  PAGE_MAX_SHIFT
458 ARM_FUNC_START(ffi_closure_trampoline_table_page)
459 .rept   PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE
460         adr ip, #-PAGE_MAX_SIZE   @ the config page is PAGE_MAX_SIZE behind the trampoline page
461         sub ip, #8                                @ account for pc bias
462         ldr     pc, [ip, #4]              @ jump to ffi_closure_SYSV or ffi_closure_VFP
463 .endr
464 ARM_FUNC_END(ffi_closure_trampoline_table_page)
465 #endif
467 #elif defined(_WIN32)
469 ARM_FUNC_START(ffi_arm_trampoline)
470 0:      adr     ip, 0b
471         stmdb   sp!, {r0, ip}
472         ldr     pc, 1f
473 1:      .long   0
474 ARM_FUNC_END(ffi_arm_trampoline)
476 #else
478 ARM_FUNC_START(ffi_arm_trampoline)
479 0:      adr     ip, 0b
480         ldr     pc, 1f
481 1:      .long   0
482 ARM_FUNC_END(ffi_arm_trampoline)
484 #endif /* FFI_EXEC_TRAMPOLINE_TABLE */
485 #endif /* __arm__ */
487 #if defined __ELF__ && defined __linux__
488         .section        .note.GNU-stack,"",%progbits
489 #endif