PageRenderTime 284ms CodeModel.GetById 160ms app.highlight 8ms RepoModel.GetById 113ms app.codeStats 0ms

/Modules/_ctypes/libffi_arm_wince/sysv.asm

http://unladen-swallow.googlecode.com/
Assembly | 228 lines | 99 code | 46 blank | 83 comment | 0 complexity | f2349a7d1d803cfb746229de0437ccdb MD5 | raw file
  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
 45FFI_TYPE_VOID       EQU 0
 46FFI_TYPE_INT        EQU 1
 47FFI_TYPE_FLOAT      EQU 2
 48FFI_TYPE_DOUBLE     EQU 3
 49;FFI_TYPE_LONGDOUBLE EQU 4
 50FFI_TYPE_UINT8      EQU 5
 51FFI_TYPE_SINT8      EQU 6
 52FFI_TYPE_UINT16     EQU 7
 53FFI_TYPE_SINT16     EQU 8
 54FFI_TYPE_UINT32     EQU 9
 55FFI_TYPE_SINT32     EQU 10
 56FFI_TYPE_UINT64     EQU 11
 57FFI_TYPE_SINT64     EQU 12
 58FFI_TYPE_STRUCT     EQU 13
 59FFI_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
154call_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
162RESERVE_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
220closure_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