1#![doc(html_root_url = "https://docs.rs/libffi-sys/4.0.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, align(8))]
260#[derive(Copy, Clone)]
261pub struct ffi_closure {
262 #[cfg(all(
267 target_vendor = "apple",
268 any(target_arch = "arm", target_arch = "aarch64")
269 ))]
270 pub trampoline_table: *mut c_void,
271 #[cfg(all(
272 target_vendor = "apple",
273 any(target_arch = "arm", target_arch = "aarch64")
274 ))]
275 pub trampoline_table_entry: *mut c_void,
276 #[cfg(not(all(
277 target_vendor = "apple",
278 any(target_arch = "arm", target_arch = "aarch64")
279 )))]
280 pub tramp: ffi_trampoline,
281 pub cif: *mut ffi_cif,
282 pub fun: Option<
283 unsafe extern "C" fn(
284 arg1: *mut ffi_cif,
285 arg2: *mut c_void,
286 arg3: *mut *mut c_void,
287 arg4: *mut c_void,
288 ),
289 >,
290 pub user_data: *mut c_void,
291 #[cfg(all(target_env = "msvc", target_arch = "x86"))]
293 pub _padding: *mut c_void,
294}
295
296impl Debug for ffi_closure {
298 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
299 let mut debug_struct = f.debug_struct("ffi_closure");
300
301 #[cfg(all(
302 target_vendor = "apple",
303 any(target_arch = "arm", target_arch = "aarch64")
304 ))]
305 debug_struct
306 .field("trampoline_table", &self.trampoline_table)
307 .field("trampoline_table_entry", &self.trampoline_table_entry);
308 #[cfg(not(all(
309 target_vendor = "apple",
310 any(target_arch = "arm", target_arch = "aarch64")
311 )))]
312 debug_struct
313 .field("tramp", unsafe { &self.tramp.tramp });
316
317 debug_struct
318 .field("cif", &self.cif)
319 .field("fun", &self.fun)
320 .field("user_data", &self.user_data)
321 .finish()
322 }
323}
324
325impl Default for ffi_closure {
326 fn default() -> Self {
327 unsafe { zeroed() }
328 }
329}
330
331#[repr(C)]
332#[derive(Copy, Clone)]
333pub struct ffi_raw_closure {
334 pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
335 pub cif: *mut ffi_cif,
336 #[cfg(not(target_arch = "x86"))]
338 pub translate_args: Option<
339 unsafe extern "C" fn(
340 arg1: *mut ffi_cif,
341 arg2: *mut c_void,
342 arg3: *mut *mut c_void,
343 arg4: *mut c_void,
344 ),
345 >,
346 #[cfg(not(target_arch = "x86"))]
347 pub this_closure: *mut c_void,
348 pub fun: Option<
349 unsafe extern "C" fn(
350 arg1: *mut ffi_cif,
351 arg2: *mut c_void,
352 arg3: *mut ffi_raw,
353 arg4: *mut c_void,
354 ),
355 >,
356 pub user_data: *mut c_void,
357}
358
359impl Debug for ffi_raw_closure {
361 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
362 let mut debug_struct = f.debug_struct("ffi_raw_closure");
363 debug_struct
364 .field("tramp", &&self.tramp[..])
365 .field("cif", &self.cif);
366
367 #[cfg(not(target_arch = "x86"))]
368 debug_struct.field("translate_args", &self.translate_args);
369 #[cfg(not(target_arch = "x86"))]
370 debug_struct.field("this_closure", &self.this_closure);
371
372 debug_struct
373 .field("fun", &self.fun)
374 .field("user_data", &self.user_data)
375 .finish()
376 }
377}
378
379impl Default for ffi_raw_closure {
380 fn default() -> Self {
381 unsafe { zeroed() }
382 }
383}
384#[repr(C)]
385#[derive(Copy, Clone)]
386pub struct ffi_java_raw_closure {
387 pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
388 pub cif: *mut ffi_cif,
389 #[cfg(not(target_arch = "x86"))]
391 pub translate_args: Option<
392 unsafe extern "C" fn(
393 arg1: *mut ffi_cif,
394 arg2: *mut c_void,
395 arg3: *mut *mut c_void,
396 arg4: *mut c_void,
397 ),
398 >,
399 #[cfg(not(target_arch = "x86"))]
400 pub this_closure: *mut c_void,
401 pub fun: Option<
402 unsafe extern "C" fn(
403 arg1: *mut ffi_cif,
404 arg2: *mut c_void,
405 arg3: *mut ffi_java_raw,
406 arg4: *mut c_void,
407 ),
408 >,
409 pub user_data: *mut c_void,
410}
411
412impl Debug for ffi_java_raw_closure {
414 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
415 let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
416 debug_struct
417 .field("tramp", &&self.tramp[..])
418 .field("cif", &self.cif);
419
420 #[cfg(not(target_arch = "x86"))]
421 debug_struct.field("translate_args", &self.translate_args);
422 #[cfg(not(target_arch = "x86"))]
423 debug_struct.field("this_closure", &self.this_closure);
424
425 debug_struct
426 .field("fun", &self.fun)
427 .field("user_data", &self.user_data)
428 .finish()
429 }
430}
431
432impl Default for ffi_java_raw_closure {
433 fn default() -> Self {
434 unsafe { zeroed() }
435 }
436}
437
438#[repr(C)]
439#[derive(Debug, Copy, Clone)]
440pub struct ffi_go_closure {
441 pub tramp: *mut c_void,
442 pub cif: *mut ffi_cif,
443 pub fun: Option<
444 unsafe extern "C" fn(
445 arg1: *mut ffi_cif,
446 arg2: *mut c_void,
447 arg3: *mut *mut c_void,
448 arg4: *mut c_void,
449 ),
450 >,
451}
452impl Default for ffi_go_closure {
453 fn default() -> Self {
454 unsafe { zeroed() }
455 }
456}
457
458extern "C" {
459 pub static mut ffi_type_void: ffi_type;
460 pub static mut ffi_type_uint8: ffi_type;
461 pub static mut ffi_type_sint8: ffi_type;
462 pub static mut ffi_type_uint16: ffi_type;
463 pub static mut ffi_type_sint16: ffi_type;
464 pub static mut ffi_type_uint32: ffi_type;
465 pub static mut ffi_type_sint32: ffi_type;
466 pub static mut ffi_type_uint64: ffi_type;
467 pub static mut ffi_type_sint64: ffi_type;
468 pub static mut ffi_type_float: ffi_type;
469 pub static mut ffi_type_double: ffi_type;
470 pub static mut ffi_type_longdouble: ffi_type;
471 pub static mut ffi_type_pointer: ffi_type;
472
473 #[cfg(all(feature = "complex", not(windows)))]
474 pub static mut ffi_type_complex_float: ffi_type;
475
476 #[cfg(all(feature = "complex", not(windows)))]
477 pub static mut ffi_type_complex_double: ffi_type;
478
479 #[cfg(all(feature = "complex", not(windows)))]
480 pub static mut ffi_type_complex_longdouble: ffi_type;
481
482 pub fn ffi_raw_call(
483 cif: *mut ffi_cif,
484 fn_: Option<unsafe extern "C" fn()>,
485 rvalue: *mut c_void,
486 avalue: *mut ffi_raw,
487 );
488
489 pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
490
491 pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
492
493 pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
494
495 #[cfg(not(target_arch = "x86"))]
497 #[deprecated = "Deprecated in libffi 3.3"]
498 pub fn ffi_java_raw_call(
499 cif: *mut ffi_cif,
500 fn_: Option<unsafe extern "C" fn()>,
501 rvalue: *mut c_void,
502 avalue: *mut ffi_java_raw,
503 );
504
505 #[deprecated = "Deprecated in libffi 3.3"]
506 pub fn ffi_java_ptrarray_to_raw(
507 cif: *mut ffi_cif,
508 args: *mut *mut c_void,
509 raw: *mut ffi_java_raw,
510 );
511
512 #[deprecated = "Deprecated in libffi 3.3"]
513 pub fn ffi_java_raw_to_ptrarray(
514 cif: *mut ffi_cif,
515 raw: *mut ffi_java_raw,
516 args: *mut *mut c_void,
517 );
518
519 #[deprecated = "Deprecated in libffi 3.3"]
520 pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
521
522 pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
523
524 pub fn ffi_closure_free(arg1: *mut c_void);
525
526 #[deprecated = "Deprecated in libffi 3.3, use `ffi_prep_closure_loc` instead"]
527 pub fn ffi_prep_closure(
528 arg1: *mut ffi_closure,
529 arg2: *mut ffi_cif,
530 fun: Option<
531 unsafe extern "C" fn(
532 arg1: *mut ffi_cif,
533 arg2: *mut c_void,
534 arg3: *mut *mut c_void,
535 arg4: *mut c_void,
536 ),
537 >,
538 user_data: *mut c_void,
539 ) -> ffi_status;
540
541 pub fn ffi_prep_closure_loc(
542 arg1: *mut ffi_closure,
543 arg2: *mut ffi_cif,
544 fun: Option<
545 unsafe extern "C" fn(
546 arg1: *mut ffi_cif,
547 arg2: *mut c_void,
548 arg3: *mut *mut c_void,
549 arg4: *mut c_void,
550 ),
551 >,
552 user_data: *mut c_void,
553 codeloc: *mut c_void,
554 ) -> ffi_status;
555
556 pub fn ffi_prep_raw_closure(
557 arg1: *mut ffi_raw_closure,
558 cif: *mut ffi_cif,
559 fun: Option<
560 unsafe extern "C" fn(
561 arg1: *mut ffi_cif,
562 arg2: *mut c_void,
563 arg3: *mut ffi_raw,
564 arg4: *mut c_void,
565 ),
566 >,
567 user_data: *mut c_void,
568 ) -> ffi_status;
569
570 pub fn ffi_prep_raw_closure_loc(
571 arg1: *mut ffi_raw_closure,
572 cif: *mut ffi_cif,
573 fun: Option<
574 unsafe extern "C" fn(
575 arg1: *mut ffi_cif,
576 arg2: *mut c_void,
577 arg3: *mut ffi_raw,
578 arg4: *mut c_void,
579 ),
580 >,
581 user_data: *mut c_void,
582 codeloc: *mut c_void,
583 ) -> ffi_status;
584
585 #[cfg(not(target_arch = "x86"))]
587 #[deprecated = "Deprecated in libffi 3.3"]
588 pub fn ffi_prep_java_raw_closure(
589 arg1: *mut ffi_java_raw_closure,
590 cif: *mut ffi_cif,
591 fun: Option<
592 unsafe extern "C" fn(
593 arg1: *mut ffi_cif,
594 arg2: *mut c_void,
595 arg3: *mut ffi_java_raw,
596 arg4: *mut c_void,
597 ),
598 >,
599 user_data: *mut c_void,
600 ) -> ffi_status;
601
602 #[cfg(not(target_arch = "x86"))]
604 #[deprecated = "Deprecated in libffi 3.3"]
605 pub fn ffi_prep_java_raw_closure_loc(
606 arg1: *mut ffi_java_raw_closure,
607 cif: *mut ffi_cif,
608 fun: Option<
609 unsafe extern "C" fn(
610 arg1: *mut ffi_cif,
611 arg2: *mut c_void,
612 arg3: *mut ffi_java_raw,
613 arg4: *mut c_void,
614 ),
615 >,
616 user_data: *mut c_void,
617 codeloc: *mut c_void,
618 ) -> ffi_status;
619
620 pub fn ffi_prep_go_closure(
621 arg1: *mut ffi_go_closure,
622 arg2: *mut ffi_cif,
623 fun: Option<
624 unsafe extern "C" fn(
625 arg1: *mut ffi_cif,
626 arg2: *mut c_void,
627 arg3: *mut *mut c_void,
628 arg4: *mut c_void,
629 ),
630 >,
631 ) -> ffi_status;
632
633 pub fn ffi_call_go(
634 cif: *mut ffi_cif,
635 fn_: Option<unsafe extern "C" fn()>,
636 rvalue: *mut c_void,
637 avalue: *mut *mut c_void,
638 closure: *mut c_void,
639 );
640
641 pub fn ffi_prep_cif(
642 cif: *mut ffi_cif,
643 abi: ffi_abi,
644 nargs: c_uint,
645 rtype: *mut ffi_type,
646 atypes: *mut *mut ffi_type,
647 ) -> ffi_status;
648
649 pub fn ffi_prep_cif_var(
650 cif: *mut ffi_cif,
651 abi: ffi_abi,
652 nfixedargs: c_uint,
653 ntotalargs: c_uint,
654 rtype: *mut ffi_type,
655 atypes: *mut *mut ffi_type,
656 ) -> ffi_status;
657
658 pub fn ffi_call(
659 cif: *mut ffi_cif,
660 fn_: Option<unsafe extern "C" fn()>,
661 rvalue: *mut c_void,
662 avalue: *mut *mut c_void,
663 );
664
665 pub fn ffi_get_struct_offsets(
666 abi: ffi_abi,
667 struct_type: *mut ffi_type,
668 offsets: *mut usize,
669 ) -> ffi_status;
670}
671
672#[cfg(all(test, feature = "std"))]
673mod test {
674 use std::{mem::transmute, ptr::addr_of_mut};
675 use std::{vec, vec::Vec};
676
677 use super::*;
678
679 extern "C" fn cast_u8_u32(x: u8) -> u32 {
680 x as u32
681 }
682
683 #[test]
684 fn test_function_sign_extension() {
685 unsafe {
686 let mut cif: ffi_cif = Default::default();
687 let mut arg_types: Vec<*mut ffi_type> = vec![addr_of_mut!(ffi_type_uint8)];
688
689 let prep_status = ffi_prep_cif(
690 &mut cif,
691 ffi_abi_FFI_DEFAULT_ABI,
692 1,
693 addr_of_mut!(ffi_type_uint8),
694 arg_types.as_mut_ptr(),
695 );
696
697 assert_eq!(prep_status, ffi_status_FFI_OK);
698
699 let mut rval: ffi_arg = 0;
700 let func = transmute::<extern "C" fn(u8) -> u32, extern "C" fn()>(cast_u8_u32);
701
702 ffi_call(
703 &mut cif,
704 Some(func),
705 &mut rval as *mut _ as *mut c_void,
706 vec![&mut 256 as *mut _ as *mut c_void].as_mut_ptr(),
707 );
708
709 assert_eq!(rval, 0);
710 }
711 }
712
713 extern "C" fn add(x: u64, y: u64) -> u64 {
714 x + y
715 }
716
717 #[test]
718 fn test_function_with_two_arguments() {
719 unsafe {
720 let mut cif: ffi_cif = Default::default();
721 let mut arg_types: Vec<*mut ffi_type> =
722 vec![addr_of_mut!(ffi_type_uint64), addr_of_mut!(ffi_type_uint64)];
723
724 let prep_status = ffi_prep_cif(
725 &mut cif,
726 ffi_abi_FFI_DEFAULT_ABI,
727 2,
728 addr_of_mut!(ffi_type_uint64),
729 arg_types.as_mut_ptr(),
730 );
731
732 assert_eq!(prep_status, ffi_status_FFI_OK);
733
734 let mut rval = 0u64;
735 let func = transmute::<extern "C" fn(u64, u64) -> u64, extern "C" fn()>(add);
736
737 ffi_call(
738 &mut cif,
739 Some(func),
740 &mut rval as *mut _ as *mut c_void,
741 vec![
742 &mut 4u64 as *mut _ as *mut c_void,
743 &mut 5u64 as *mut _ as *mut c_void,
744 ]
745 .as_mut_ptr(),
746 );
747
748 assert_eq!(rval, 9);
749 }
750 }
751
752 #[cfg(not(feature = "system"))]
760 #[test]
761 fn verify_ffi_closure_size() {
762 extern "C" {
763 fn ffi_get_closure_size() -> usize;
764 }
765
766 unsafe {
767 assert_eq!(std::mem::size_of::<ffi_closure>(), ffi_get_closure_size());
768 }
769 }
770}