Home | History | Annotate | Download | only in libffi_arm_wince
      1 ; -----------------------------------------------------------------------
      2 ;  sysv.S - Copyright (c) 1998 Red Hat, Inc.
      3 ;  
      4 ;  ARM Foreign Function Interface 
      5 ;
      6 ;  Permission is hereby granted, free of charge, to any person obtaining
      7 ;  a copy of this software and associated documentation files (the
      8 ;  ``Software''), to deal in the Software without restriction, including
      9 ;  without limitation the rights to use, copy, modify, merge, publish,
     10 ;  distribute, sublicense, and/or sell copies of the Software, and to
     11 ;  permit persons to whom the Software is furnished to do so, subject to
     12 ;  the following conditions:
     13 ;
     14 ;  The above copyright notice and this permission notice shall be included
     15 ;  in all copies or substantial portions of the Software.
     16 ;
     17 ;  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18 ;  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19 ;  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20 ;  IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21 ;  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22 ;  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23 ;  OTHER DEALINGS IN THE SOFTWARE.
     24 ;  ----------------------------------------------------------------------- */
     25 
     26 ;#define LIBFFI_ASM     
     27 ;#include <fficonfig.h>
     28 ;#include <ffi.h>
     29 ;#ifdef HAVE_MACHINE_ASM_H
     30 ;#include <machine/asm.h>
     31 ;#else
     32 ;#ifdef __USER_LABEL_PREFIX__
     33 ;#define CONCAT1(a, b) CONCAT2(a, b)
     34 ;#define CONCAT2(a, b) a ## b
     35 
     36 ;/* Use the right prefix for global labels.  */
     37 ;#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
     38 ;#else
     39 ;#define CNAME(x) x
     40 ;#endif
     41 ;#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
     42 ;#endif
     43 
     44 
     45 FFI_TYPE_VOID       EQU 0
     46 FFI_TYPE_INT        EQU 1
     47 FFI_TYPE_FLOAT      EQU 2
     48 FFI_TYPE_DOUBLE     EQU 3
     49 ;FFI_TYPE_LONGDOUBLE EQU 4
     50 FFI_TYPE_UINT8      EQU 5
     51 FFI_TYPE_SINT8      EQU 6
     52 FFI_TYPE_UINT16     EQU 7
     53 FFI_TYPE_SINT16     EQU 8
     54 FFI_TYPE_UINT32     EQU 9
     55 FFI_TYPE_SINT32     EQU 10
     56 FFI_TYPE_UINT64     EQU 11
     57 FFI_TYPE_SINT64     EQU 12
     58 FFI_TYPE_STRUCT     EQU 13
     59 FFI_TYPE_POINTER    EQU 14
     60 
     61 ; WinCE always uses software floating point (I think)
     62 __SOFTFP__ EQU {TRUE}
     63 
     64 
     65     AREA |.text|, CODE, ARM     ; .text
     66 
     67 
     68     ; a1:   ffi_prep_args
     69     ; a2:   &ecif
     70     ; a3:   cif->bytes
     71     ; a4:   fig->flags
     72     ; sp+0: ecif.rvalue
     73     ; sp+4: fn
     74 
     75     ; This assumes we are using gas.
     76 ;ENTRY(ffi_call_SYSV)
     77 
     78     EXPORT |ffi_call_SYSV|
     79 
     80 |ffi_call_SYSV| PROC
     81 
     82     ; Save registers
     83     stmfd sp!, {a1-a4, fp, lr}
     84     mov   fp, sp
     85 
     86     ; Make room for all of the new args.
     87     sub   sp, fp, a3
     88 
     89     ; Place all of the ffi_prep_args in position
     90     mov   ip, a1
     91     mov   a1, sp
     92     ;     a2 already set
     93 
     94     ; And call
     95     mov   lr, pc
     96     mov   pc, ip
     97 
     98     ; move first 4 parameters in registers
     99     ldr   a1, [sp, #0]
    100     ldr   a2, [sp, #4]
    101     ldr   a3, [sp, #8]
    102     ldr   a4, [sp, #12]
    103 
    104     ; and adjust stack
    105     ldr   ip, [fp, #8]
    106     cmp   ip, #16
    107     movge ip, #16
    108     add   sp, sp, ip
    109 
    110     ; call function
    111     mov   lr, pc
    112     ldr   pc, [fp, #28]
    113 
    114     ; Remove the space we pushed for the args
    115     mov   sp, fp
    116 
    117     ; Load a3 with the pointer to storage for the return value
    118     ldr   a3, [sp, #24]
    119 
    120     ; Load a4 with the return type code 
    121     ldr   a4, [sp, #12]
    122 
    123     ; If the return value pointer is NULL, assume no return value.
    124     cmp   a3, #0
    125     beq   call_epilogue
    126 
    127 ; return INT
    128     cmp   a4, #FFI_TYPE_INT
    129     streq a1, [a3]
    130     beq   call_epilogue
    131 
    132 ; return FLOAT
    133     cmp     a4, #FFI_TYPE_FLOAT
    134     [ __SOFTFP__                    ;ifdef __SOFTFP__
    135     streq   a1, [a3]
    136     |                               ;else
    137     stfeqs  f0, [a3]
    138     ]                               ;endif
    139     beq     call_epilogue
    140 
    141 ; return DOUBLE or LONGDOUBLE
    142     cmp     a4, #FFI_TYPE_DOUBLE
    143     [ __SOFTFP__                    ;ifdef __SOFTFP__
    144     stmeqia a3, {a1, a2}
    145     |                               ;else
    146     stfeqd  f0, [a3]
    147     ]                               ;endif
    148     beq     call_epilogue
    149 
    150 ; return SINT64 or UINT64
    151     cmp     a4, #FFI_TYPE_SINT64
    152     stmeqia a3, {a1, a2}
    153 
    154 call_epilogue
    155     ldmfd   sp!, {a1-a4, fp, pc}
    156 
    157 ;.ffi_call_SYSV_end:
    158     ;.size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
    159     ENDP
    160 
    161 
    162 RESERVE_RETURN EQU 16
    163 
    164     ; This function is called by the trampoline
    165     ; It is NOT callable from C
    166     ; ip = pointer to struct ffi_closure
    167 
    168     IMPORT |ffi_closure_SYSV_inner|
    169 
    170     EXPORT |ffi_closure_SYSV|
    171 |ffi_closure_SYSV| PROC
    172 
    173     ; Store the argument registers on the stack
    174     stmfd   sp!, {a1-a4}
    175     ; Push the return address onto the stack
    176     stmfd   sp!, {lr}
    177 
    178     mov     a1, ip            ; first arg = address of ffi_closure
    179     add     a2, sp, #4        ; second arg = sp+4 (points to saved a1)
    180 
    181     ; Allocate space for a non-struct return value
    182     sub     sp, sp, #RESERVE_RETURN
    183     mov     a3, sp            ; third arg = return value address
    184 
    185     ; static unsigned int
    186     ; ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue)
    187     bl      ffi_closure_SYSV_inner
    188     ; a1 now contains the return type code 
    189 
    190     ; At this point the return value is on the stack
    191     ; Transfer it to the correct registers if necessary
    192 
    193 ; return INT
    194     cmp     a1, #FFI_TYPE_INT
    195     ldreq   a1, [sp]
    196     beq     closure_epilogue
    197 
    198 ; return FLOAT
    199     cmp     a1, #FFI_TYPE_FLOAT
    200     [ __SOFTFP__                    ;ifdef __SOFTFP__
    201     ldreq   a1, [sp]
    202     |                               ;else
    203     stfeqs  f0, [sp]
    204     ]                               ;endif
    205     beq     closure_epilogue
    206 
    207 ; return DOUBLE or LONGDOUBLE
    208     cmp     a1, #FFI_TYPE_DOUBLE
    209     [ __SOFTFP__                    ;ifdef __SOFTFP__
    210     ldmeqia sp, {a1, a2}
    211     |                               ;else
    212     stfeqd  f0, [sp]
    213     ]                               ;endif
    214     beq     closure_epilogue
    215 
    216 ; return SINT64 or UINT64
    217     cmp     a1, #FFI_TYPE_SINT64
    218     ldmeqia sp, {a1, a2}
    219 
    220 closure_epilogue
    221     add     sp, sp, #RESERVE_RETURN   ; remove return value buffer
    222     ldmfd   sp!, {ip}         ; ip = pop return address
    223     add     sp, sp, #16       ; remove saved argument registers {a1-a4} from the stack
    224     mov     pc, ip            ; return
    225 
    226     ENDP    ; ffi_closure_SYSV
    227 
    228     END
    229