1#![doc(html_root_url = "https://docs.rs/libffi-sys/4.2.0")]
2#![allow(non_camel_case_types)]
49#![allow(non_snake_case)]
50#![allow(non_upper_case_globals)]
51#![allow(improper_ctypes)]
52#![allow(unused_imports)]
53#![no_std]
54
55#[cfg(feature = "std")]
56extern crate std;
57
58use core::ffi::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void};
59use core::fmt::{self, Debug, Formatter};
60use core::mem::zeroed;
61
62mod arch;
63pub use arch::*;
64
65pub type ffi_arg = c_ulong;
67pub type ffi_sarg = c_long;
69pub type ffi_abi = u32;
71pub type ffi_status = u32;
73pub type ffi_type_enum = u16;
74
75pub const FFI_64_BIT_MAX: u64 = 9_223_372_036_854_775_807;
76pub const FFI_CLOSURES: u32 = 1;
77pub const FFI_SIZEOF_ARG: usize = core::mem::size_of::<c_long>();
78pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG;
80
81pub const FFI_TYPE_VOID: u16 = 0;
82pub const FFI_TYPE_INT: u16 = 1;
83pub const FFI_TYPE_FLOAT: u16 = 2;
84pub const FFI_TYPE_DOUBLE: u16 = 3;
85pub const FFI_TYPE_LONGDOUBLE: u16 = 4;
86pub const FFI_TYPE_UINT8: u16 = 5;
87pub const FFI_TYPE_SINT8: u16 = 6;
88pub const FFI_TYPE_UINT16: u16 = 7;
89pub const FFI_TYPE_SINT16: u16 = 8;
90pub const FFI_TYPE_UINT32: u16 = 9;
91pub const FFI_TYPE_SINT32: u16 = 10;
92pub const FFI_TYPE_UINT64: u16 = 11;
93pub const FFI_TYPE_SINT64: u16 = 12;
94pub const FFI_TYPE_STRUCT: u16 = 13;
95pub const FFI_TYPE_POINTER: u16 = 14;
96pub const FFI_TYPE_COMPLEX: u16 = 15;
97pub const FFI_TYPE_LAST: u16 = 15;
98
99pub const ffi_status_FFI_OK: ffi_status = 0;
100pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1;
101pub const ffi_status_FFI_BAD_ABI: ffi_status = 2;
102pub const ffi_status_FFI_BAD_ARGTYPE: ffi_status = 3;
103
104pub const ffi_type_enum_STRUCT: ffi_type_enum = 13;
105pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15;
106
107#[repr(C)]
156#[derive(Copy, Clone)]
157pub struct ffi_type {
158 pub size: usize,
159 pub alignment: c_ushort,
160 pub type_: c_ushort,
161 pub elements: *mut *mut ffi_type,
162}
163
164impl Default for ffi_type {
165 fn default() -> Self {
166 unsafe { zeroed() }
167 }
168}
169
170#[repr(C)]
175#[derive(Debug, Copy, Clone)]
176pub struct ffi_cif {
177 pub abi: ffi_abi,
178 pub nargs: c_uint,
179 pub arg_types: *mut *mut ffi_type,
180 pub rtype: *mut ffi_type,
181 pub bytes: c_uint,
182 pub flags: c_uint,
183 #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
184 pub is_variadic: c_uint,
185 #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
186 pub aarch64_nfixedargs: c_uint,
187 #[cfg(target_arch = "arm")]
188 pub vfp_used: c_int,
189 #[cfg(target_arch = "arm")]
190 pub vfp_reg_free: c_ushort,
191 #[cfg(target_arch = "arm")]
192 pub vfp_nargs: c_ushort,
193 #[cfg(target_arch = "arm")]
194 pub vfp_args: [c_schar; 16],
195 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
196 pub nfixedargs: c_uint,
197 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
198 pub riscv_nfixedargs: c_uint,
199 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
200 pub riscv_unused: c_uint,
201 #[cfg(target_arch = "sparc64")]
202 pub nfixedargs: c_uint,
203 #[cfg(target_arch = "loongarch64")]
204 pub loongarch_nfixedargs: c_uint,
205 #[cfg(target_arch = "loongarch64")]
206 pub loongarch_unused: c_uint,
207 #[cfg(any(
208 target_arch = "mips",
209 target_arch = "mips32r6",
210 target_arch = "mips64",
211 target_arch = "mips64r6"
212 ))]
213 pub mips_nfixedargs: c_uint,
214}
215
216impl Default for ffi_cif {
217 fn default() -> Self {
218 unsafe { zeroed() }
219 }
220}
221
222#[repr(C)]
223#[derive(Copy, Clone)]
224pub union ffi_raw {
225 pub sint: ffi_sarg,
226 pub uint: ffi_arg,
227 pub flt: f32,
228 pub data: [c_char; FFI_SIZEOF_ARG],
229 pub ptr: *mut c_void,
230}
231
232impl Default for ffi_raw {
233 fn default() -> Self {
234 unsafe { zeroed() }
235 }
236}
237
238pub type ffi_java_raw = ffi_raw;
239
240#[repr(C)]
241#[derive(Copy, Clone)]
242pub union ffi_trampoline {
243 pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
244 pub ftramp: *mut c_void,
245}
246
247#[repr(C)]
260#[cfg_attr(target_env = "msvc", repr(align(8)))]
261#[derive(Copy, Clone)]
262pub struct ffi_closure {
263 #[cfg(all(
268 target_vendor = "apple",
269 any(target_arch = "arm", target_arch = "aarch64")
270 ))]
271 pub trampoline_table: *mut c_void,
272 #[cfg(all(
273 target_vendor = "apple",
274 any(target_arch = "arm", target_arch = "aarch64")
275 ))]
276 pub trampoline_table_entry: *mut c_void,
277 #[cfg(not(all(
278 target_vendor = "apple",
279 any(target_arch = "arm", target_arch = "aarch64")
280 )))]
281 pub tramp: ffi_trampoline,
282 pub cif: *mut ffi_cif,
283 pub fun: Option<
284 unsafe extern "C" fn(
285 arg1: *mut ffi_cif,
286 arg2: *mut c_void,
287 arg3: *mut *mut c_void,
288 arg4: *mut c_void,
289 ),
290 >,
291 pub user_data: *mut c_void,
292 #[cfg(all(target_env = "msvc", target_arch = "x86"))]
294 pub _padding: *mut c_void,
295}
296
297impl Debug for ffi_closure {
299 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
300 let mut debug_struct = f.debug_struct("ffi_closure");
301
302 #[cfg(all(
303 target_vendor = "apple",
304 any(target_arch = "arm", target_arch = "aarch64")
305 ))]
306 debug_struct
307 .field("trampoline_table", &self.trampoline_table)
308 .field("trampoline_table_entry", &self.trampoline_table_entry);
309 #[cfg(not(all(
310 target_vendor = "apple",
311 any(target_arch = "arm", target_arch = "aarch64")
312 )))]
313 debug_struct
314 .field("tramp", unsafe { &self.tramp.tramp });
317
318 debug_struct
319 .field("cif", &self.cif)
320 .field("fun", &self.fun)
321 .field("user_data", &self.user_data)
322 .finish()
323 }
324}
325
326impl Default for ffi_closure {
327 fn default() -> Self {
328 unsafe { zeroed() }
329 }
330}
331
332#[repr(C)]
333#[derive(Copy, Clone)]
334pub struct ffi_raw_closure {
335 pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
336 pub cif: *mut ffi_cif,
337 #[cfg(not(target_arch = "x86"))]
339 pub translate_args: Option<
340 unsafe extern "C" fn(
341 arg1: *mut ffi_cif,
342 arg2: *mut c_void,
343 arg3: *mut *mut c_void,
344 arg4: *mut c_void,
345 ),
346 >,
347 #[cfg(not(target_arch = "x86"))]
348 pub this_closure: *mut c_void,
349 pub fun: Option<
350 unsafe extern "C" fn(
351 arg1: *mut ffi_cif,
352 arg2: *mut c_void,
353 arg3: *mut ffi_raw,
354 arg4: *mut c_void,
355 ),
356 >,
357 pub user_data: *mut c_void,
358}
359
360impl Debug for ffi_raw_closure {
362 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
363 let mut debug_struct = f.debug_struct("ffi_raw_closure");
364 debug_struct
365 .field("tramp", &&self.tramp[..])
366 .field("cif", &self.cif);
367
368 #[cfg(not(target_arch = "x86"))]
369 debug_struct.field("translate_args", &self.translate_args);
370 #[cfg(not(target_arch = "x86"))]
371 debug_struct.field("this_closure", &self.this_closure);
372
373 debug_struct
374 .field("fun", &self.fun)
375 .field("user_data", &self.user_data)
376 .finish()
377 }
378}
379
380impl Default for ffi_raw_closure {
381 fn default() -> Self {
382 unsafe { zeroed() }
383 }
384}
385#[repr(C)]
386#[derive(Copy, Clone)]
387pub struct ffi_java_raw_closure {
388 pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
389 pub cif: *mut ffi_cif,
390 #[cfg(not(target_arch = "x86"))]
392 pub translate_args: Option<
393 unsafe extern "C" fn(
394 arg1: *mut ffi_cif,
395 arg2: *mut c_void,
396 arg3: *mut *mut c_void,
397 arg4: *mut c_void,
398 ),
399 >,
400 #[cfg(not(target_arch = "x86"))]
401 pub this_closure: *mut c_void,
402 pub fun: Option<
403 unsafe extern "C" fn(
404 arg1: *mut ffi_cif,
405 arg2: *mut c_void,
406 arg3: *mut ffi_java_raw,
407 arg4: *mut c_void,
408 ),
409 >,
410 pub user_data: *mut c_void,
411}
412
413impl Debug for ffi_java_raw_closure {
415 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
416 let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
417 debug_struct
418 .field("tramp", &&self.tramp[..])
419 .field("cif", &self.cif);
420
421 #[cfg(not(target_arch = "x86"))]
422 debug_struct.field("translate_args", &self.translate_args);
423 #[cfg(not(target_arch = "x86"))]
424 debug_struct.field("this_closure", &self.this_closure);
425
426 debug_struct
427 .field("fun", &self.fun)
428 .field("user_data", &self.user_data)
429 .finish()
430 }
431}
432
433impl Default for ffi_java_raw_closure {
434 fn default() -> Self {
435 unsafe { zeroed() }
436 }
437}
438
439#[repr(C)]
440#[derive(Debug, Copy, Clone)]
441pub struct ffi_go_closure {
442 pub tramp: *mut c_void,
443 pub cif: *mut ffi_cif,
444 pub fun: Option<
445 unsafe extern "C" fn(
446 arg1: *mut ffi_cif,
447 arg2: *mut c_void,
448 arg3: *mut *mut c_void,
449 arg4: *mut c_void,
450 ),
451 >,
452}
453impl Default for ffi_go_closure {
454 fn default() -> Self {
455 unsafe { zeroed() }
456 }
457}
458
459extern "C" {
460 pub static mut ffi_type_void: ffi_type;
461 pub static mut ffi_type_uint8: ffi_type;
462 pub static mut ffi_type_sint8: ffi_type;
463 pub static mut ffi_type_uint16: ffi_type;
464 pub static mut ffi_type_sint16: ffi_type;
465 pub static mut ffi_type_uint32: ffi_type;
466 pub static mut ffi_type_sint32: ffi_type;
467 pub static mut ffi_type_uint64: ffi_type;
468 pub static mut ffi_type_sint64: ffi_type;
469 pub static mut ffi_type_float: ffi_type;
470 pub static mut ffi_type_double: ffi_type;
471 pub static mut ffi_type_longdouble: ffi_type;
472 pub static mut ffi_type_pointer: ffi_type;
473
474 #[cfg(all(feature = "complex", not(windows)))]
475 pub static mut ffi_type_complex_float: ffi_type;
476
477 #[cfg(all(feature = "complex", not(windows)))]
478 pub static mut ffi_type_complex_double: ffi_type;
479
480 #[cfg(all(feature = "complex", not(windows)))]
481 pub static mut ffi_type_complex_longdouble: ffi_type;
482
483 pub fn ffi_raw_call(
484 cif: *mut ffi_cif,
485 fn_: Option<unsafe extern "C" fn()>,
486 rvalue: *mut c_void,
487 avalue: *mut ffi_raw,
488 );
489
490 pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
491
492 pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
493
494 pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
495
496 #[cfg(not(target_arch = "x86"))]
498 #[deprecated = "Deprecated in libffi 3.3"]
499 pub fn ffi_java_raw_call(
500 cif: *mut ffi_cif,
501 fn_: Option<unsafe extern "C" fn()>,
502 rvalue: *mut c_void,
503 avalue: *mut ffi_java_raw,
504 );
505
506 #[deprecated = "Deprecated in libffi 3.3"]
507 pub fn ffi_java_ptrarray_to_raw(
508 cif: *mut ffi_cif,
509 args: *mut *mut c_void,
510 raw: *mut ffi_java_raw,
511 );
512
513 #[deprecated = "Deprecated in libffi 3.3"]
514 pub fn ffi_java_raw_to_ptrarray(
515 cif: *mut ffi_cif,
516 raw: *mut ffi_java_raw,
517 args: *mut *mut c_void,
518 );
519
520 #[deprecated = "Deprecated in libffi 3.3"]
521 pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
522
523 pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
524
525 pub fn ffi_closure_free(arg1: *mut c_void);
526
527 #[deprecated = "Deprecated in libffi 3.3, use `ffi_prep_closure_loc` instead"]
528 pub fn ffi_prep_closure(
529 arg1: *mut ffi_closure,
530 arg2: *mut ffi_cif,
531 fun: Option<
532 unsafe extern "C" fn(
533 arg1: *mut ffi_cif,
534 arg2: *mut c_void,
535 arg3: *mut *mut c_void,
536 arg4: *mut c_void,
537 ),
538 >,
539 user_data: *mut c_void,
540 ) -> ffi_status;
541
542 pub fn ffi_prep_closure_loc(
543 arg1: *mut ffi_closure,
544 arg2: *mut ffi_cif,
545 fun: Option<
546 unsafe extern "C" fn(
547 arg1: *mut ffi_cif,
548 arg2: *mut c_void,
549 arg3: *mut *mut c_void,
550 arg4: *mut c_void,
551 ),
552 >,
553 user_data: *mut c_void,
554 codeloc: *mut c_void,
555 ) -> ffi_status;
556
557 pub fn ffi_prep_raw_closure(
558 arg1: *mut ffi_raw_closure,
559 cif: *mut ffi_cif,
560 fun: Option<
561 unsafe extern "C" fn(
562 arg1: *mut ffi_cif,
563 arg2: *mut c_void,
564 arg3: *mut ffi_raw,
565 arg4: *mut c_void,
566 ),
567 >,
568 user_data: *mut c_void,
569 ) -> ffi_status;
570
571 pub fn ffi_prep_raw_closure_loc(
572 arg1: *mut ffi_raw_closure,
573 cif: *mut ffi_cif,
574 fun: Option<
575 unsafe extern "C" fn(
576 arg1: *mut ffi_cif,
577 arg2: *mut c_void,
578 arg3: *mut ffi_raw,
579 arg4: *mut c_void,
580 ),
581 >,
582 user_data: *mut c_void,
583 codeloc: *mut c_void,
584 ) -> ffi_status;
585
586 #[cfg(not(target_arch = "x86"))]
588 #[deprecated = "Deprecated in libffi 3.3"]
589 pub fn ffi_prep_java_raw_closure(
590 arg1: *mut ffi_java_raw_closure,
591 cif: *mut ffi_cif,
592 fun: Option<
593 unsafe extern "C" fn(
594 arg1: *mut ffi_cif,
595 arg2: *mut c_void,
596 arg3: *mut ffi_java_raw,
597 arg4: *mut c_void,
598 ),
599 >,
600 user_data: *mut c_void,
601 ) -> ffi_status;
602
603 #[cfg(not(target_arch = "x86"))]
605 #[deprecated = "Deprecated in libffi 3.3"]
606 pub fn ffi_prep_java_raw_closure_loc(
607 arg1: *mut ffi_java_raw_closure,
608 cif: *mut ffi_cif,
609 fun: Option<
610 unsafe extern "C" fn(
611 arg1: *mut ffi_cif,
612 arg2: *mut c_void,
613 arg3: *mut ffi_java_raw,
614 arg4: *mut c_void,
615 ),
616 >,
617 user_data: *mut c_void,
618 codeloc: *mut c_void,
619 ) -> ffi_status;
620
621 pub fn ffi_prep_go_closure(
622 arg1: *mut ffi_go_closure,
623 arg2: *mut ffi_cif,
624 fun: Option<
625 unsafe extern "C" fn(
626 arg1: *mut ffi_cif,
627 arg2: *mut c_void,
628 arg3: *mut *mut c_void,
629 arg4: *mut c_void,
630 ),
631 >,
632 ) -> ffi_status;
633
634 pub fn ffi_call_go(
635 cif: *mut ffi_cif,
636 fn_: Option<unsafe extern "C" fn()>,
637 rvalue: *mut c_void,
638 avalue: *mut *mut c_void,
639 closure: *mut c_void,
640 );
641
642 pub fn ffi_prep_cif(
643 cif: *mut ffi_cif,
644 abi: ffi_abi,
645 nargs: c_uint,
646 rtype: *mut ffi_type,
647 atypes: *mut *mut ffi_type,
648 ) -> ffi_status;
649
650 pub fn ffi_prep_cif_var(
651 cif: *mut ffi_cif,
652 abi: ffi_abi,
653 nfixedargs: c_uint,
654 ntotalargs: c_uint,
655 rtype: *mut ffi_type,
656 atypes: *mut *mut ffi_type,
657 ) -> ffi_status;
658
659 pub fn ffi_call(
660 cif: *mut ffi_cif,
661 fn_: Option<unsafe extern "C" fn()>,
662 rvalue: *mut c_void,
663 avalue: *mut *mut c_void,
664 );
665
666 pub fn ffi_get_struct_offsets(
667 abi: ffi_abi,
668 struct_type: *mut ffi_type,
669 offsets: *mut usize,
670 ) -> ffi_status;
671}
672
673#[cfg(all(test, feature = "std"))]
674mod test {
675 use std::{mem::transmute, ptr::addr_of_mut};
676 use std::{vec, vec::Vec};
677
678 use super::*;
679
680 extern "C" fn cast_u8_u32(x: u8) -> u32 {
681 x as u32
682 }
683
684 #[test]
685 fn test_function_sign_extension() {
686 unsafe {
687 let mut cif: ffi_cif = Default::default();
688 let mut arg_types: Vec<*mut ffi_type> = vec![addr_of_mut!(ffi_type_uint8)];
689
690 let prep_status = ffi_prep_cif(
691 &mut cif,
692 ffi_abi_FFI_DEFAULT_ABI,
693 1,
694 addr_of_mut!(ffi_type_uint8),
695 arg_types.as_mut_ptr(),
696 );
697
698 assert_eq!(prep_status, ffi_status_FFI_OK);
699
700 let mut rval: ffi_arg = 0;
701 let func = transmute::<extern "C" fn(u8) -> u32, extern "C" fn()>(cast_u8_u32);
702
703 ffi_call(
704 &mut cif,
705 Some(func),
706 &mut rval as *mut _ as *mut c_void,
707 vec![&mut 256 as *mut _ as *mut c_void].as_mut_ptr(),
708 );
709
710 assert_eq!(rval, 0);
711 }
712 }
713
714 extern "C" fn add(x: u64, y: u64) -> u64 {
715 x + y
716 }
717
718 #[test]
719 fn test_function_with_two_arguments() {
720 unsafe {
721 let mut cif: ffi_cif = Default::default();
722 let mut arg_types: Vec<*mut ffi_type> =
723 vec![addr_of_mut!(ffi_type_uint64), addr_of_mut!(ffi_type_uint64)];
724
725 let prep_status = ffi_prep_cif(
726 &mut cif,
727 ffi_abi_FFI_DEFAULT_ABI,
728 2,
729 addr_of_mut!(ffi_type_uint64),
730 arg_types.as_mut_ptr(),
731 );
732
733 assert_eq!(prep_status, ffi_status_FFI_OK);
734
735 let mut rval = 0u64;
736 let func = transmute::<extern "C" fn(u64, u64) -> u64, extern "C" fn()>(add);
737
738 ffi_call(
739 &mut cif,
740 Some(func),
741 &mut rval as *mut _ as *mut c_void,
742 vec![
743 &mut 4u64 as *mut _ as *mut c_void,
744 &mut 5u64 as *mut _ as *mut c_void,
745 ]
746 .as_mut_ptr(),
747 );
748
749 assert_eq!(rval, 9);
750 }
751 }
752
753 #[cfg(not(feature = "system"))]
761 #[test]
762 fn verify_ffi_closure_size() {
763 extern "C" {
764 fn ffi_get_closure_size() -> usize;
765 }
766
767 unsafe {
768 assert_eq!(std::mem::size_of::<ffi_closure>(), ffi_get_closure_size());
769 }
770 }
771}