• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
3        Copyright (c) 2011 Plausible Labs Cooperative, Inc.
4        Copyright (c) 2019 Microsoft Corporation.
5
6   ARM Foreign Function Interface
7
8   Permission is hereby granted, free of charge, to any person obtaining
9   a copy of this software and associated documentation files (the
10   ``Software''), to deal in the Software without restriction, including
11   without limitation the rights to use, copy, modify, merge, publish,
12   distribute, sublicense, and/or sell copies of the Software, and to
13   permit persons to whom the Software is furnished to do so, subject to
14   the following conditions:
15
16   The above copyright notice and this permission notice shall be included
17   in all copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26   DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#define LIBFFI_ASM
30#include <fficonfig.h>
31#include <ffi.h>
32#include <ffi_cfi.h>
33#include "internal.h"
34#include "ksarm.h"
35
36
37        ; 8 byte aligned AREA to support 8 byte aligned jump tables
38        MACRO
39        NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler
40
41        ; compute the function's labels
42        __DeriveFunctionLabels $FuncName
43
44        ; determine the area we will put the function into
45__FuncArea   SETS    "|.text|"
46        IF "$AreaName" != ""
47__FuncArea   SETS    "$AreaName"
48        ENDIF
49
50        ; set up the exception handler itself
51__FuncExceptionHandler SETS ""
52        IF "$ExceptHandler" != ""
53__FuncExceptionHandler SETS    "|$ExceptHandler|"
54        ENDIF
55
56        ; switch to the specified area, jump tables require 8 byte alignment
57        AREA    $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY
58
59        ; export the function name
60        __ExportProc $FuncName
61
62        ; flush any pending literal pool stuff
63        ROUT
64
65        ; reset the state of the unwind code tracking
66        __ResetUnwindState
67
68        MEND
69
70;        MACRO
71;        TABLE_ENTRY $Type, $Table
72;$Type_$Table
73;        MEND
74
75#define E(index,table) return_##index##_##table
76
77    ; r0:   stack
78    ; r1:   frame
79    ; r2:   fn
80    ; r3:   vfp_used
81
82    ; fake entry point exists only to generate exists only to
83    ; generate .pdata for exception unwinding
84    NESTED_ENTRY_FFI ffi_call_VFP_fake
85    PROLOG_PUSH  {r11, lr}          ; save fp and lr for unwind
86
87    ALTERNATE_ENTRY ffi_call_VFP
88    cmp    r3, #3                   ; load only d0 if possible
89    vldrle d0, [r0]
90    vldmgt r0, {d0-d7}
91    add    r0, r0, #64              ; discard the vfp register args
92    b ffi_call_SYSV
93    NESTED_END ffi_call_VFP_fake
94
95    ; fake entry point exists only to generate exists only to
96    ; generate .pdata for exception unwinding
97    NESTED_ENTRY_FFI ffi_call_SYSV_fake
98    PROLOG_PUSH  {r11, lr}          ; save fp and lr for unwind
99
100    ALTERNATE_ENTRY ffi_call_SYSV
101    stm    r1, {fp, lr}
102    mov    fp, r1
103
104    mov    sp, r0                   ; install the stack pointer
105    mov    lr, r2                   ; move the fn pointer out of the way
106    ldr    ip, [fp, #16]            ; install the static chain
107    ldmia  sp!, {r0-r3}             ; move first 4 parameters in registers.
108    blx    lr                       ; call fn
109
110    ; Load r2 with the pointer to storage for the return value
111    ; Load r3 with the return type code
112    ldr    r2, [fp, #8]
113    ldr    r3, [fp, #12]
114
115    ; Deallocate the stack with the arguments.
116    mov    sp, fp
117
118    ; Store values stored in registers.
119    ALIGN 8
120    lsl     r3, #3
121    add     r3, r3, pc
122    add     r3, #8
123    mov     pc, r3
124
125
126E(ARM_TYPE_VFP_S, ffi_call)
127    ALIGN 8
128    vstr s0, [r2]
129    pop    {fp,pc}
130E(ARM_TYPE_VFP_D, ffi_call)
131    ALIGN 8
132    vstr d0, [r2]
133    pop    {fp,pc}
134E(ARM_TYPE_VFP_N, ffi_call)
135    ALIGN 8
136    vstm r2, {d0-d3}
137    pop    {fp,pc}
138E(ARM_TYPE_INT64, ffi_call)
139    ALIGN 8
140    str    r1, [r2, #4]
141    nop
142E(ARM_TYPE_INT, ffi_call)
143    ALIGN 8
144    str    r0, [r2]
145    pop    {fp,pc}
146E(ARM_TYPE_VOID, ffi_call)
147    ALIGN 8
148    pop    {fp,pc}
149    nop
150E(ARM_TYPE_STRUCT, ffi_call)
151    ALIGN 8
152    cmp r3, #ARM_TYPE_STRUCT
153    pop    {fp,pc}
154    NESTED_END ffi_call_SYSV_fake
155
156    IMPORT |ffi_closure_inner_SYSV|
157    /*
158    int ffi_closure_inner_SYSV
159    (
160        cif,        ; r0
161        fun,        ; r1
162        user_data,  ; r2
163        frame       ; r3
164    )
165    */
166
167    NESTED_ENTRY_FFI ffi_go_closure_SYSV
168    stmdb   sp!, {r0-r3}            ; save argument regs
169    ldr     r0, [ip, #4]            ; load cif
170    ldr     r1, [ip, #8]            ; load fun
171    mov     r2, ip                  ; load user_data
172    b       ffi_go_closure_SYSV_0
173    NESTED_END ffi_go_closure_SYSV
174
175    ; r3:    ffi_closure
176
177    ; fake entry point exists only to generate exists only to
178    ; generate .pdata for exception unwinding
179    NESTED_ENTRY_FFI ffi_closure_SYSV_fake
180    PROLOG_PUSH  {r11, lr}          ; save fp and lr for unwind
181    ALTERNATE_ENTRY ffi_closure_SYSV
182    ldmfd   sp!, {ip,r0}            ; restore fp (r0 is used for stack alignment)
183    stmdb   sp!, {r0-r3}            ; save argument regs
184
185    ldr     r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET]    ; ffi_closure->cif
186    ldr     r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4]  ; ffi_closure->fun
187    ldr     r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8]  ; ffi_closure->user_data
188
189    ALTERNATE_ENTRY ffi_go_closure_SYSV_0
190    add     ip, sp, #16             ; compute entry sp
191
192    sub     sp, sp, #64+32          ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32)
193    mov     r3, sp                  ; set frame parameter
194    stmdb   sp!, {ip,lr}
195
196    bl      ffi_closure_inner_SYSV  ; call the Python closure
197
198                                    ; Load values returned in registers.
199    add     r2, sp, #64+8           ; address of closure_frame->result
200    bl      ffi_closure_ret         ; move result to correct register or memory for type
201
202    ldmfd   sp!, {ip,lr}
203    mov     sp, ip                  ; restore stack pointer
204    mov     pc, lr
205    NESTED_END ffi_closure_SYSV_fake
206
207    IMPORT |ffi_closure_inner_VFP|
208    /*
209    int ffi_closure_inner_VFP
210    (
211        cif,        ; r0
212        fun,        ; r1
213        user_data,  ; r2
214        frame       ; r3
215    )
216    */
217
218    NESTED_ENTRY_FFI ffi_go_closure_VFP
219    stmdb   sp!, {r0-r3}			; save argument regs
220    ldr	r0, [ip, #4]			; load cif
221    ldr	r1, [ip, #8]			; load fun
222    mov	r2, ip				; load user_data
223    b	ffi_go_closure_VFP_0
224    NESTED_END ffi_go_closure_VFP
225
226    ; fake entry point exists only to generate exists only to
227    ; generate .pdata for exception unwinding
228    ; r3:    closure
229    NESTED_ENTRY_FFI ffi_closure_VFP_fake
230    PROLOG_PUSH  {r11, lr}          ; save fp and lr for unwind
231
232    ALTERNATE_ENTRY ffi_closure_VFP
233    ldmfd   sp!, {ip,r0}            ; restore fp (r0 is used for stack alignment)
234    stmdb   sp!, {r0-r3}            ; save argument regs
235
236    ldr     r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET]    ; load cif
237    ldr     r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4]  ; load fun
238    ldr     r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8]  ; load user_data
239
240    ALTERNATE_ENTRY ffi_go_closure_VFP_0
241    add     ip, sp, #16             ; compute entry sp
242    sub     sp, sp, #32             ; save space for closure_frame->result
243    vstmdb  sp!, {d0-d7}            ; push closure_frame->vfp_space
244
245    mov     r3, sp                  ; save closure_frame
246    stmdb   sp!, {ip,lr}
247
248    bl      ffi_closure_inner_VFP
249
250    ; Load values returned in registers.
251    add     r2, sp, #64+8           ; load result
252    bl      ffi_closure_ret
253    ldmfd   sp!, {ip,lr}
254    mov     sp, ip                  ; restore stack pointer
255    mov     pc, lr
256    NESTED_END ffi_closure_VFP_fake
257
258/* Load values returned in registers for both closure entry points.
259   Note that we use LDM with SP in the register set.  This is deprecated
260   by ARM, but not yet unpredictable.  */
261
262    NESTED_ENTRY_FFI ffi_closure_ret
263    stmdb sp!, {fp,lr}
264
265    ALIGN 8
266    lsl     r0, #3
267    add     r0, r0, pc
268    add     r0, #8
269    mov     pc, r0
270
271E(ARM_TYPE_VFP_S, ffi_closure)
272    ALIGN 8
273    vldr s0, [r2]
274    b call_epilogue
275E(ARM_TYPE_VFP_D, ffi_closure)
276    ALIGN 8
277    vldr d0, [r2]
278    b call_epilogue
279E(ARM_TYPE_VFP_N, ffi_closure)
280    ALIGN 8
281    vldm r2, {d0-d3}
282    b call_epilogue
283E(ARM_TYPE_INT64, ffi_closure)
284    ALIGN 8
285    ldr    r1, [r2, #4]
286    nop
287E(ARM_TYPE_INT, ffi_closure)
288    ALIGN 8
289    ldr    r0, [r2]
290    b call_epilogue
291E(ARM_TYPE_VOID, ffi_closure)
292    ALIGN 8
293    b call_epilogue
294    nop
295E(ARM_TYPE_STRUCT, ffi_closure)
296    ALIGN 8
297    b call_epilogue
298call_epilogue
299    ldmfd sp!, {fp,pc}
300    NESTED_END ffi_closure_ret
301
302    AREA |.trampoline|, DATA, THUMB, READONLY
303    EXPORT |ffi_arm_trampoline|
304|ffi_arm_trampoline| DATA
305thisproc    adr    ip, thisproc
306            stmdb  sp!, {ip, r0}
307            ldr    pc, [pc, #0]
308            DCD    0
309            ;ENDP
310
311    END