1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
3 2015 Andrew Waterman <waterman@cs.berkeley.edu>
4 2018 Stef O'Rear <sorear2@gmail.com>
5 Based on MIPS N32/64 port
7 RISC-V Foreign Function Interface
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 ``Software''), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28 ----------------------------------------------------------------------- */
31 #include <ffi_common.h>
36 #if __riscv_float_abi_double
38 #define ABI_FLOAT double
39 #elif __riscv_float_abi_single
41 #define ABI_FLOAT float
46 #define MAXCOPYARG (2 * sizeof(double))
48 typedef struct call_context
54 /* used by the assembly code to in-place construct its own stack frame */
58 typedef struct call_builder
66 /* integer (not pointer) less than ABI XLEN */
67 /* FFI_TYPE_INT does not appear to be used */
68 #if __SIZEOF_POINTER__ == 8
69 #define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64)
71 #define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32)
76 char as_elements
, type1
, offset2
, type2
;
80 #define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= FFI_TYPE_DOUBLE)
82 #define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT)
85 static ffi_type
**flatten_struct(ffi_type
*in
, ffi_type
**out
, ffi_type
**out_end
) {
87 if (out
== out_end
) return out
;
88 if (in
->type
!= FFI_TYPE_STRUCT
) {
91 for (i
= 0; in
->elements
[i
]; i
++)
92 out
= flatten_struct(in
->elements
[i
], out
, out_end
);
97 /* Structs with at most two fields after flattening, one of which is of
98 floating point type, are passed in multiple registers if sufficient
99 registers are available. */
100 static float_struct_info
struct_passed_as_elements(call_builder
*cb
, ffi_type
*top
) {
101 float_struct_info ret
= {0, 0, 0, 0};
103 int num_floats
, num_ints
;
104 int num_fields
= flatten_struct(top
, fields
, fields
+ 3) - fields
;
106 if (num_fields
== 1) {
107 if (IS_FLOAT(fields
[0]->type
)) {
109 ret
.type1
= fields
[0]->type
;
111 } else if (num_fields
== 2) {
112 num_floats
= IS_FLOAT(fields
[0]->type
) + IS_FLOAT(fields
[1]->type
);
113 num_ints
= IS_INT(fields
[0]->type
) + IS_INT(fields
[1]->type
);
114 if (num_floats
== 0 || num_floats
+ num_ints
!= 2)
116 if (cb
->used_float
+ num_floats
> NARGREG
|| cb
->used_integer
+ (2 - num_floats
) > NARGREG
)
118 if (!IS_FLOAT(fields
[0]->type
) && !IS_FLOAT(fields
[1]->type
))
121 ret
.type1
= fields
[0]->type
;
122 ret
.type2
= fields
[1]->type
;
123 ret
.offset2
= ALIGN(fields
[0]->size
, fields
[1]->alignment
);
131 /* allocates a single register, float register, or XLEN-sized stack slot to a datum */
132 static void marshal_atom(call_builder
*cb
, int type
, void *data
) {
135 case FFI_TYPE_UINT8
: value
= *(uint8_t *)data
; break;
136 case FFI_TYPE_SINT8
: value
= *(int8_t *)data
; break;
137 case FFI_TYPE_UINT16
: value
= *(uint16_t *)data
; break;
138 case FFI_TYPE_SINT16
: value
= *(int16_t *)data
; break;
139 /* 32-bit quantities are always sign-extended in the ABI */
140 case FFI_TYPE_UINT32
: value
= *(int32_t *)data
; break;
141 case FFI_TYPE_SINT32
: value
= *(int32_t *)data
; break;
142 #if __SIZEOF_POINTER__ == 8
143 case FFI_TYPE_UINT64
: value
= *(uint64_t *)data
; break;
144 case FFI_TYPE_SINT64
: value
= *(int64_t *)data
; break;
146 case FFI_TYPE_POINTER
: value
= *(size_t *)data
; break;
148 /* float values may be recoded in an implementation-defined way
149 by hardware conforming to 2.1 or earlier, so use asm to
150 reinterpret floats as doubles */
153 asm("" : "=f"(cb
->aregs
->fa
[cb
->used_float
++]) : "0"(*(float *)data
));
157 case FFI_TYPE_DOUBLE
:
158 asm("" : "=f"(cb
->aregs
->fa
[cb
->used_float
++]) : "0"(*(double *)data
));
161 default: FFI_ASSERT(0); break;
164 if (cb
->used_integer
== NARGREG
) {
165 *cb
->used_stack
++ = value
;
167 cb
->aregs
->a
[cb
->used_integer
++] = value
;
171 static void unmarshal_atom(call_builder
*cb
, int type
, void *data
) {
176 asm("" : "=f"(*(float *)data
) : "0"(cb
->aregs
->fa
[cb
->used_float
++]));
180 case FFI_TYPE_DOUBLE
:
181 asm("" : "=f"(*(double *)data
) : "0"(cb
->aregs
->fa
[cb
->used_float
++]));
186 if (cb
->used_integer
== NARGREG
) {
187 value
= *cb
->used_stack
++;
189 value
= cb
->aregs
->a
[cb
->used_integer
++];
193 case FFI_TYPE_UINT8
: *(uint8_t *)data
= value
; break;
194 case FFI_TYPE_SINT8
: *(uint8_t *)data
= value
; break;
195 case FFI_TYPE_UINT16
: *(uint16_t *)data
= value
; break;
196 case FFI_TYPE_SINT16
: *(uint16_t *)data
= value
; break;
197 case FFI_TYPE_UINT32
: *(uint32_t *)data
= value
; break;
198 case FFI_TYPE_SINT32
: *(uint32_t *)data
= value
; break;
199 #if __SIZEOF_POINTER__ == 8
200 case FFI_TYPE_UINT64
: *(uint64_t *)data
= value
; break;
201 case FFI_TYPE_SINT64
: *(uint64_t *)data
= value
; break;
203 case FFI_TYPE_POINTER
: *(size_t *)data
= value
; break;
204 default: FFI_ASSERT(0); break;
208 /* adds an argument to a call, or a not by reference return value */
209 static void marshal(call_builder
*cb
, ffi_type
*type
, int var
, void *data
) {
213 if (!var
&& type
->type
== FFI_TYPE_STRUCT
) {
214 float_struct_info fsi
= struct_passed_as_elements(cb
, type
);
215 if (fsi
.as_elements
) {
216 marshal_atom(cb
, fsi
.type1
, data
);
218 marshal_atom(cb
, fsi
.type2
, ((char*)data
) + fsi
.offset2
);
223 if (!var
&& cb
->used_float
< NARGREG
&& IS_FLOAT(type
->type
)) {
224 marshal_atom(cb
, type
->type
, data
);
229 if (type
->size
> 2 * __SIZEOF_POINTER__
) {
230 /* pass by reference */
231 marshal_atom(cb
, FFI_TYPE_POINTER
, &data
);
232 } else if (IS_INT(type
->type
) || type
->type
== FFI_TYPE_POINTER
) {
233 marshal_atom(cb
, type
->type
, data
);
235 /* overlong integers, soft-float floats, and structs without special
236 float handling are treated identically from this point on */
238 /* variadics are aligned even in registers */
239 if (type
->alignment
> __SIZEOF_POINTER__
) {
241 cb
->used_integer
= ALIGN(cb
->used_integer
, 2);
242 cb
->used_stack
= (size_t *)ALIGN(cb
->used_stack
, 2*__SIZEOF_POINTER__
);
245 memcpy(realign
, data
, type
->size
);
247 marshal_atom(cb
, FFI_TYPE_POINTER
, realign
);
248 if (type
->size
> __SIZEOF_POINTER__
)
249 marshal_atom(cb
, FFI_TYPE_POINTER
, realign
+ 1);
253 /* for arguments passed by reference returns the pointer, otherwise the arg is copied (up to MAXCOPYARG bytes) */
254 static void *unmarshal(call_builder
*cb
, ffi_type
*type
, int var
, void *data
) {
259 if (!var
&& type
->type
== FFI_TYPE_STRUCT
) {
260 float_struct_info fsi
= struct_passed_as_elements(cb
, type
);
261 if (fsi
.as_elements
) {
262 unmarshal_atom(cb
, fsi
.type1
, data
);
264 unmarshal_atom(cb
, fsi
.type2
, ((char*)data
) + fsi
.offset2
);
269 if (!var
&& cb
->used_float
< NARGREG
&& IS_FLOAT(type
->type
)) {
270 unmarshal_atom(cb
, type
->type
, data
);
275 if (type
->size
> 2 * __SIZEOF_POINTER__
) {
276 /* pass by reference */
277 unmarshal_atom(cb
, FFI_TYPE_POINTER
, (char*)&pointer
);
279 } else if (IS_INT(type
->type
) || type
->type
== FFI_TYPE_POINTER
) {
280 unmarshal_atom(cb
, type
->type
, data
);
283 /* overlong integers, soft-float floats, and structs without special
284 float handling are treated identically from this point on */
286 /* variadics are aligned even in registers */
287 if (type
->alignment
> __SIZEOF_POINTER__
) {
289 cb
->used_integer
= ALIGN(cb
->used_integer
, 2);
290 cb
->used_stack
= (size_t *)ALIGN(cb
->used_stack
, 2*__SIZEOF_POINTER__
);
294 unmarshal_atom(cb
, FFI_TYPE_POINTER
, realign
);
295 if (type
->size
> __SIZEOF_POINTER__
)
296 unmarshal_atom(cb
, FFI_TYPE_POINTER
, realign
+ 1);
297 memcpy(data
, realign
, type
->size
);
302 static int passed_by_ref(call_builder
*cb
, ffi_type
*type
, int var
) {
304 if (!var
&& type
->type
== FFI_TYPE_STRUCT
) {
305 float_struct_info fsi
= struct_passed_as_elements(cb
, type
);
306 if (fsi
.as_elements
) return 0;
310 return type
->size
> 2 * __SIZEOF_POINTER__
;
313 /* Perform machine dependent cif processing */
314 ffi_status
ffi_prep_cif_machdep(ffi_cif
*cif
) {
315 cif
->riscv_nfixedargs
= cif
->nargs
;
319 /* Perform machine dependent cif processing when we have a variadic function */
321 ffi_status
ffi_prep_cif_machdep_var(ffi_cif
*cif
, unsigned int nfixedargs
, unsigned int ntotalargs
) {
322 cif
->riscv_nfixedargs
= nfixedargs
;
326 /* Low level routine for calling functions */
327 extern void ffi_call_asm (void *stack
, struct call_context
*regs
,
328 void (*fn
) (void), void *closure
) FFI_HIDDEN
;
331 ffi_call_int (ffi_cif
*cif
, void (*fn
) (void), void *rvalue
, void **avalue
,
334 /* this is a conservative estimate, assuming a complex return value and
335 that all remaining arguments are long long / __int128 */
336 size_t arg_bytes
= cif
->nargs
<= 3 ? 0 :
337 ALIGN(2 * sizeof(size_t) * (cif
->nargs
- 3), STKALIGN
);
338 size_t rval_bytes
= 0;
339 if (rvalue
== NULL
&& cif
->rtype
->size
> 2*__SIZEOF_POINTER__
)
340 rval_bytes
= ALIGN(cif
->rtype
->size
, STKALIGN
);
341 size_t alloc_size
= arg_bytes
+ rval_bytes
+ sizeof(call_context
);
343 /* the assembly code will deallocate all stack data at lower addresses
344 than the argument region, so we need to allocate the frame and the
345 return value after the arguments in a single allocation */
347 /* Argument region must be 16-byte aligned */
348 if (_Alignof(max_align_t
) >= STKALIGN
) {
349 /* since sizeof long double is normally 16, the compiler will
350 guarantee alloca alignment to at least that much */
351 alloc_base
= (size_t)alloca(alloc_size
);
353 alloc_base
= ALIGN(alloca(alloc_size
+ STKALIGN
- 1), STKALIGN
);
357 rvalue
= (void*)(alloc_base
+ arg_bytes
);
360 cb
.used_float
= cb
.used_integer
= 0;
361 cb
.aregs
= (call_context
*)(alloc_base
+ arg_bytes
+ rval_bytes
);
362 cb
.used_stack
= (void*)alloc_base
;
364 int return_by_ref
= passed_by_ref(&cb
, cif
->rtype
, 0);
366 marshal(&cb
, &ffi_type_pointer
, 0, &rvalue
);
369 for (i
= 0; i
< cif
->nargs
; i
++)
370 marshal(&cb
, cif
->arg_types
[i
], i
>= cif
->riscv_nfixedargs
, avalue
[i
]);
372 ffi_call_asm ((void *) alloc_base
, cb
.aregs
, fn
, closure
);
374 cb
.used_float
= cb
.used_integer
= 0;
375 if (!return_by_ref
&& rvalue
)
376 unmarshal(&cb
, cif
->rtype
, 0, rvalue
);
380 ffi_call (ffi_cif
*cif
, void (*fn
) (void), void *rvalue
, void **avalue
)
382 ffi_call_int(cif
, fn
, rvalue
, avalue
, NULL
);
386 ffi_call_go (ffi_cif
*cif
, void (*fn
) (void), void *rvalue
,
387 void **avalue
, void *closure
)
389 ffi_call_int(cif
, fn
, rvalue
, avalue
, closure
);
392 extern void ffi_closure_asm(void) FFI_HIDDEN
;
394 ffi_status
ffi_prep_closure_loc(ffi_closure
*closure
, ffi_cif
*cif
, void (*fun
)(ffi_cif
*,void*,void**,void*), void *user_data
, void *codeloc
)
396 uint32_t *tramp
= (uint32_t *) &closure
->tramp
[0];
397 uint64_t fn
= (uint64_t) (uintptr_t) ffi_closure_asm
;
399 if (cif
->abi
<= FFI_FIRST_ABI
|| cif
->abi
>= FFI_LAST_ABI
)
402 /* we will call ffi_closure_inner with codeloc, not closure, but as long
403 as the memory is readable it should work */
405 tramp
[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */
406 #if __SIZEOF_POINTER__ == 8
407 tramp
[1] = 0x01033383; /* ld t2, 16(t1) */
409 tramp
[1] = 0x01032383; /* lw t2, 16(t1) */
411 tramp
[2] = 0x00038067; /* jr t2 */
412 tramp
[3] = 0x00000013; /* nop */
418 closure
->user_data
= user_data
;
420 __builtin___clear_cache(codeloc
, codeloc
+ FFI_TRAMPOLINE_SIZE
);
425 extern void ffi_go_closure_asm (void) FFI_HIDDEN
;
428 ffi_prep_go_closure (ffi_go_closure
*closure
, ffi_cif
*cif
,
429 void (*fun
) (ffi_cif
*, void *, void **, void *))
431 if (cif
->abi
<= FFI_FIRST_ABI
|| cif
->abi
>= FFI_LAST_ABI
)
434 closure
->tramp
= (void *) ffi_go_closure_asm
;
441 /* Called by the assembly code with aregs pointing to saved argument registers
442 and stack pointing to the stacked arguments. Return values passed in
443 registers will be reloaded from aregs. */
445 ffi_closure_inner (ffi_cif
*cif
,
446 void (*fun
) (ffi_cif
*, void *, void **, void *),
448 size_t *stack
, call_context
*aregs
)
450 void **avalue
= alloca(cif
->nargs
* sizeof(void*));
451 /* storage for arguments which will be copied by unmarshal(). We could
452 theoretically avoid the copies in many cases and use at most 128 bytes
453 of memory, but allocating disjoint storage for each argument is
455 char *astorage
= alloca(cif
->nargs
* MAXCOPYARG
);
462 cb
.used_integer
= cb
.used_float
= 0;
463 cb
.used_stack
= stack
;
465 return_by_ref
= passed_by_ref(&cb
, cif
->rtype
, 0);
467 unmarshal(&cb
, &ffi_type_pointer
, 0, &rvalue
);
469 rvalue
= alloca(cif
->rtype
->size
);
471 for (i
= 0; i
< cif
->nargs
; i
++)
472 avalue
[i
] = unmarshal(&cb
, cif
->arg_types
[i
],
473 i
>= cif
->riscv_nfixedargs
, astorage
+ i
*MAXCOPYARG
);
475 fun (cif
, rvalue
, avalue
, user_data
);
477 if (!return_by_ref
&& cif
->rtype
->type
!= FFI_TYPE_VOID
) {
478 cb
.used_integer
= cb
.used_float
= 0;
479 marshal(&cb
, cif
->rtype
, 0, rvalue
);