libffi_sys/
lib.rs

1#![doc(html_root_url = "https://docs.rs/libffi-sys/3.3.3")]
2//! Low-level Rust bindings for [libffi](https://sourceware.org/libffi/)
3//!
4//! The C libffi library provides two main facilities: assembling calls
5//! to functions dynamically, and creating closures that can be called
6//! as ordinary C functions.
7//!
8//! This is a mostly undocumented wrapper, originally generated by bindgen then
9//! cleaned up manually, intended as the basis for higher-level bindings.
10//!
11//! See [the libffi crate](https://crates.io/crates/libffi/) for a
12//! higher-level API.
13//!
14//! # Usage
15//!
16//! `libffi-sys` can either build its own copy of the libffi C library [from
17//! github](https://github.com/libffi/libffi) or it can link against your
18//! system's C libffi. By default it builds its own because many systems ship
19//! with an old C libffi; this requires that you have a working make, C
20//! compiler, automake, and autoconf first. If your system libffi is recent
21//! enough (v3.2.1 as of October 2019), you can instead enable the `system`
22//! feature flag to use that.
23//!
24//! On Windows, it is not supported to link against a shared libffi library as
25//! it is generally not available. Automake and autoconf are not required when
26//! building for the `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`
27//! targets.
28//!
29//! If you want this crate to build a C libffi for you, add
30//!
31//! ```toml
32//! [dependencies]
33//! libffi-sys = "3.3.3"
34//! ```
35//!
36//! to your `Cargo.toml`. If you want to use your system C libffi, then
37//!
38//! ```toml
39//! [dependencies.libffi-sys]
40//! version = "3.3.3"
41//! features = ["system"]
42//! ```
43//!
44//! to your `Cargo.toml` instead.
45//!
46//! This crate supports Rust version 1.78 and later.
47
48#![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
54use core::ffi::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void};
55use core::fmt::{self, Debug, Formatter};
56use core::mem::zeroed;
57
58mod arch;
59pub use arch::*;
60
61/// The smallest unsigned integer type returned by [`ffi_call`].
62pub type ffi_arg = c_ulong;
63/// The smallest signed integer type returned by [`ffi_call`].
64pub type ffi_sarg = c_long;
65/// The type used to convey the ABI of a function.
66pub type ffi_abi = u32;
67/// The return type of `libffi`'s functions that may return an error.
68pub type ffi_status = u32;
69pub type ffi_type_enum = u32;
70
71pub const FFI_64_BIT_MAX: u64 = 9_223_372_036_854_775_807;
72pub const FFI_CLOSURES: u32 = 1;
73pub const FFI_SIZEOF_ARG: usize = core::mem::size_of::<c_long>();
74// NOTE: This only differs from FFI_SIZEOF_ARG on ILP platforms, which Rust does not support
75pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG;
76
77pub const FFI_TYPE_VOID: u32 = 0;
78pub const FFI_TYPE_INT: u32 = 1;
79pub const FFI_TYPE_FLOAT: u32 = 2;
80pub const FFI_TYPE_DOUBLE: u32 = 3;
81pub const FFI_TYPE_LONGDOUBLE: u32 = 4;
82pub const FFI_TYPE_UINT8: u32 = 5;
83pub const FFI_TYPE_SINT8: u32 = 6;
84pub const FFI_TYPE_UINT16: u32 = 7;
85pub const FFI_TYPE_SINT16: u32 = 8;
86pub const FFI_TYPE_UINT32: u32 = 9;
87pub const FFI_TYPE_SINT32: u32 = 10;
88pub const FFI_TYPE_UINT64: u32 = 11;
89pub const FFI_TYPE_SINT64: u32 = 12;
90pub const FFI_TYPE_STRUCT: u32 = 13;
91pub const FFI_TYPE_POINTER: u32 = 14;
92pub const FFI_TYPE_COMPLEX: u32 = 15;
93pub const FFI_TYPE_LAST: u32 = 15;
94
95pub const ffi_status_FFI_OK: ffi_status = 0;
96pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1;
97pub const ffi_status_FFI_BAD_ABI: ffi_status = 2;
98pub const ffi_status_FFI_BAD_ARGTYPE: ffi_status = 3;
99
100pub const ffi_type_enum_STRUCT: ffi_type_enum = 13;
101pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15;
102
103/// A struct used by `libffi` to describe types and their memory layout.
104///
105/// New `ffi_type` variables should only be constructed for describing the
106/// layout of custom structs. For plain scalar types it is recommended to refer
107/// to the `static` variables defined by libffi instead of creating new
108/// `ffi_type`s.
109///
110/// When creating new `ffi_type`s, the `size` and `alignment` fields should be
111/// left at their default values, as `libffi` will fill out these fields during
112/// [`ffi_prep_cif`].
113///
114/// # Example
115///
116/// ```
117/// use std::ptr;
118///
119/// #[repr(C)]
120/// struct CustomStruct {
121///     num: u32,
122///     num2: i64,
123///     float_num: f32,
124/// }
125///
126/// // We need to describe the types of the values in `CustomStruct`. The order
127/// // must be the same as the order in the struct definition. Note that this
128/// // array must be alive and at the same address for the entire lifetime of
129/// // the resulting `ffi_type`.
130/// let mut elements_array = unsafe {[
131///     // `libffi::low::types::uint32`, `sint64`, and `float` can be used
132///     // instead if using libffi (not -sys)
133///     ptr::addr_of_mut!(libffi_sys::ffi_type_uint32),
134///     ptr::addr_of_mut!(libffi_sys::ffi_type_sint64),
135///     ptr::addr_of_mut!(libffi_sys::ffi_type_float),
136///     // The last element in the array must be a `NULL` since `ffi_type` does
137///     // not store the number of elements in the struct.
138///     ptr::null_mut(),
139/// ]};
140///
141/// let mut custom_struct_description = libffi_sys::ffi_type {
142///     // `libffi::low::type_tag::STRUCT` can be used instead if using libffi
143///     type_: libffi_sys::FFI_TYPE_STRUCT as u16,
144///     elements: elements_array.as_mut_ptr(),
145///     ..Default::default()
146/// };
147///
148/// // `custom_struct_description` can now be used in a [`ffi_cif`] to send
149/// // `CustomStruct` as an argument or receive a `CustomStruct` as response.
150/// ```
151#[repr(C)]
152#[derive(Copy, Clone)]
153pub struct ffi_type {
154    pub size: usize,
155    pub alignment: c_ushort,
156    pub type_: c_ushort,
157    pub elements: *mut *mut ffi_type,
158}
159
160impl Default for ffi_type {
161    fn default() -> Self {
162        unsafe { zeroed() }
163    }
164}
165
166/// A struct used by `libffi` to describe a function's ABI and type signature.
167///
168/// It is recommended to not fill out the fields in a `ffi_cif` manually, but
169/// rather supply the correct arguments to [`ffi_prep_cif`].
170#[repr(C)]
171#[derive(Debug, Copy, Clone)]
172pub struct ffi_cif {
173    pub abi: ffi_abi,
174    pub nargs: c_uint,
175    pub arg_types: *mut *mut ffi_type,
176    pub rtype: *mut ffi_type,
177    pub bytes: c_uint,
178    pub flags: c_uint,
179    #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
180    pub is_variadic: c_uint,
181    #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
182    pub aarch64_nfixedargs: c_uint,
183    #[cfg(target_arch = "arm")]
184    pub vfp_used: c_int,
185    #[cfg(target_arch = "arm")]
186    pub vfp_reg_free: c_ushort,
187    #[cfg(target_arch = "arm")]
188    pub vfp_nargs: c_ushort,
189    #[cfg(target_arch = "arm")]
190    pub vfp_args: [c_schar; 16],
191    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
192    pub nfixedargs: c_uint,
193    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
194    pub riscv_nfixedargs: c_uint,
195    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
196    pub riscv_unused: c_uint,
197    #[cfg(target_arch = "sparc64")]
198    pub nfixedargs: c_uint,
199    #[cfg(target_arch = "loongarch64")]
200    pub loongarch_nfixedargs: c_uint,
201    #[cfg(target_arch = "loongarch64")]
202    pub loongarch_unused: c_uint,
203    #[cfg(any(
204        target_arch = "mips",
205        target_arch = "mips32r6",
206        target_arch = "mips64",
207        target_arch = "mips64r6"
208    ))]
209    pub mips_nfixedargs: c_uint,
210}
211
212impl Default for ffi_cif {
213    fn default() -> Self {
214        unsafe { zeroed() }
215    }
216}
217
218#[repr(C, align(64))]
219#[derive(Copy, Clone)]
220pub union ffi_raw {
221    pub sint: ffi_sarg,
222    pub uint: ffi_arg,
223    pub flt: f32,
224    pub data: [c_char; FFI_SIZEOF_ARG],
225    pub ptr: *mut c_void,
226}
227
228impl Default for ffi_raw {
229    fn default() -> Self {
230        unsafe { zeroed() }
231    }
232}
233
234pub type ffi_java_raw = ffi_raw;
235
236#[repr(C, align(64))]
237#[derive(Copy, Clone)]
238pub union ffi_trampoline {
239    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
240    pub ftramp: *mut c_void,
241}
242
243/// A struct used by `libffi` to describe and manage closures.
244///
245/// Closures in libffi can be used to create function pointers to functions with
246/// arbitrary signatures that can also have some custom data embedded.
247///
248/// `ffi_closure` should not be created manually. Instead, [`ffi_closure_alloc`]
249/// should be invoked to allocate memory for the `ffi_closure` before its fields
250/// are populated by [`ffi_prep_closure`].
251#[repr(C)]
252#[derive(Copy, Clone)]
253pub struct ffi_closure {
254    pub tramp: ffi_trampoline,
255    pub cif: *mut ffi_cif,
256    pub fun: Option<
257        unsafe extern "C" fn(
258            arg1: *mut ffi_cif,
259            arg2: *mut c_void,
260            arg3: *mut *mut c_void,
261            arg4: *mut c_void,
262        ),
263    >,
264    pub user_data: *mut c_void,
265}
266
267/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
268impl Debug for ffi_closure {
269    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
270        f.debug_struct("ffi_closure")
271            .field("tramp", unsafe { &&self.tramp.tramp[..] })
272            .field("cif", &self.cif)
273            .field("fun", &self.fun)
274            .field("user_data", &self.user_data)
275            .finish()
276    }
277}
278
279impl Default for ffi_closure {
280    fn default() -> Self {
281        unsafe { zeroed() }
282    }
283}
284
285#[repr(C)]
286#[derive(Copy, Clone)]
287pub struct ffi_raw_closure {
288    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
289    pub cif: *mut ffi_cif,
290    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
291    #[cfg(not(target_arch = "x86"))]
292    pub translate_args: Option<
293        unsafe extern "C" fn(
294            arg1: *mut ffi_cif,
295            arg2: *mut c_void,
296            arg3: *mut *mut c_void,
297            arg4: *mut c_void,
298        ),
299    >,
300    #[cfg(not(target_arch = "x86"))]
301    pub this_closure: *mut c_void,
302    pub fun: Option<
303        unsafe extern "C" fn(
304            arg1: *mut ffi_cif,
305            arg2: *mut c_void,
306            arg3: *mut ffi_raw,
307            arg4: *mut c_void,
308        ),
309    >,
310    pub user_data: *mut c_void,
311}
312
313/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
314impl Debug for ffi_raw_closure {
315    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
316        let mut debug_struct = f.debug_struct("ffi_raw_closure");
317        debug_struct
318            .field("tramp", &&self.tramp[..])
319            .field("cif", &self.cif);
320
321        #[cfg(not(target_arch = "x86"))]
322        debug_struct.field("translate_args", &self.translate_args);
323        #[cfg(not(target_arch = "x86"))]
324        debug_struct.field("this_closure", &self.this_closure);
325
326        debug_struct
327            .field("fun", &self.fun)
328            .field("user_data", &self.user_data)
329            .finish()
330    }
331}
332
333impl Default for ffi_raw_closure {
334    fn default() -> Self {
335        unsafe { zeroed() }
336    }
337}
338#[repr(C)]
339#[derive(Copy, Clone)]
340pub struct ffi_java_raw_closure {
341    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
342    pub cif: *mut ffi_cif,
343    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L386
344    #[cfg(not(target_arch = "x86"))]
345    pub translate_args: Option<
346        unsafe extern "C" fn(
347            arg1: *mut ffi_cif,
348            arg2: *mut c_void,
349            arg3: *mut *mut c_void,
350            arg4: *mut c_void,
351        ),
352    >,
353    #[cfg(not(target_arch = "x86"))]
354    pub this_closure: *mut c_void,
355    pub fun: Option<
356        unsafe extern "C" fn(
357            arg1: *mut ffi_cif,
358            arg2: *mut c_void,
359            arg3: *mut ffi_java_raw,
360            arg4: *mut c_void,
361        ),
362    >,
363    pub user_data: *mut c_void,
364}
365
366/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
367impl Debug for ffi_java_raw_closure {
368    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
369        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
370        debug_struct
371            .field("tramp", &&self.tramp[..])
372            .field("cif", &self.cif);
373
374        #[cfg(not(target_arch = "x86"))]
375        debug_struct.field("translate_args", &self.translate_args);
376        #[cfg(not(target_arch = "x86"))]
377        debug_struct.field("this_closure", &self.this_closure);
378
379        debug_struct
380            .field("fun", &self.fun)
381            .field("user_data", &self.user_data)
382            .finish()
383    }
384}
385
386impl Default for ffi_java_raw_closure {
387    fn default() -> Self {
388        unsafe { zeroed() }
389    }
390}
391
392#[repr(C)]
393#[derive(Debug, Copy, Clone)]
394pub struct ffi_go_closure {
395    pub tramp: *mut c_void,
396    pub cif: *mut ffi_cif,
397    pub fun: Option<
398        unsafe extern "C" fn(
399            arg1: *mut ffi_cif,
400            arg2: *mut c_void,
401            arg3: *mut *mut c_void,
402            arg4: *mut c_void,
403        ),
404    >,
405}
406impl Default for ffi_go_closure {
407    fn default() -> Self {
408        unsafe { zeroed() }
409    }
410}
411
412extern "C" {
413    pub static mut ffi_type_void: ffi_type;
414    pub static mut ffi_type_uint8: ffi_type;
415    pub static mut ffi_type_sint8: ffi_type;
416    pub static mut ffi_type_uint16: ffi_type;
417    pub static mut ffi_type_sint16: ffi_type;
418    pub static mut ffi_type_uint32: ffi_type;
419    pub static mut ffi_type_sint32: ffi_type;
420    pub static mut ffi_type_uint64: ffi_type;
421    pub static mut ffi_type_sint64: ffi_type;
422    pub static mut ffi_type_float: ffi_type;
423    pub static mut ffi_type_double: ffi_type;
424    pub static mut ffi_type_longdouble: ffi_type;
425    pub static mut ffi_type_pointer: ffi_type;
426
427    #[cfg(feature = "complex")]
428    pub static mut ffi_type_complex_float: ffi_type;
429
430    #[cfg(feature = "complex")]
431    pub static mut ffi_type_complex_double: ffi_type;
432
433    #[cfg(feature = "complex")]
434    pub static mut ffi_type_complex_longdouble: ffi_type;
435
436    pub fn ffi_raw_call(
437        cif: *mut ffi_cif,
438        fn_: Option<unsafe extern "C" fn()>,
439        rvalue: *mut c_void,
440        avalue: *mut ffi_raw,
441    );
442
443    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
444
445    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
446
447    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
448
449    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L302
450    #[cfg(not(target_arch = "x86"))]
451    #[deprecated = "Deprecated in libffi 3.3"]
452    pub fn ffi_java_raw_call(
453        cif: *mut ffi_cif,
454        fn_: Option<unsafe extern "C" fn()>,
455        rvalue: *mut c_void,
456        avalue: *mut ffi_java_raw,
457    );
458
459    #[deprecated = "Deprecated in libffi 3.3"]
460    pub fn ffi_java_ptrarray_to_raw(
461        cif: *mut ffi_cif,
462        args: *mut *mut c_void,
463        raw: *mut ffi_java_raw,
464    );
465
466    #[deprecated = "Deprecated in libffi 3.3"]
467    pub fn ffi_java_raw_to_ptrarray(
468        cif: *mut ffi_cif,
469        raw: *mut ffi_java_raw,
470        args: *mut *mut c_void,
471    );
472
473    #[deprecated = "Deprecated in libffi 3.3"]
474    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
475
476    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
477
478    pub fn ffi_closure_free(arg1: *mut c_void);
479
480    #[deprecated = "Deprecated in libffi 3.3, use `ffi_prep_closure_loc` instead"]
481    pub fn ffi_prep_closure(
482        arg1: *mut ffi_closure,
483        arg2: *mut ffi_cif,
484        fun: Option<
485            unsafe extern "C" fn(
486                arg1: *mut ffi_cif,
487                arg2: *mut c_void,
488                arg3: *mut *mut c_void,
489                arg4: *mut c_void,
490            ),
491        >,
492        user_data: *mut c_void,
493    ) -> ffi_status;
494
495    pub fn ffi_prep_closure_loc(
496        arg1: *mut ffi_closure,
497        arg2: *mut ffi_cif,
498        fun: Option<
499            unsafe extern "C" fn(
500                arg1: *mut ffi_cif,
501                arg2: *mut c_void,
502                arg3: *mut *mut c_void,
503                arg4: *mut c_void,
504            ),
505        >,
506        user_data: *mut c_void,
507        codeloc: *mut c_void,
508    ) -> ffi_status;
509
510    pub fn ffi_prep_raw_closure(
511        arg1: *mut ffi_raw_closure,
512        cif: *mut ffi_cif,
513        fun: Option<
514            unsafe extern "C" fn(
515                arg1: *mut ffi_cif,
516                arg2: *mut c_void,
517                arg3: *mut ffi_raw,
518                arg4: *mut c_void,
519            ),
520        >,
521        user_data: *mut c_void,
522    ) -> ffi_status;
523
524    pub fn ffi_prep_raw_closure_loc(
525        arg1: *mut ffi_raw_closure,
526        cif: *mut ffi_cif,
527        fun: Option<
528            unsafe extern "C" fn(
529                arg1: *mut ffi_cif,
530                arg2: *mut c_void,
531                arg3: *mut ffi_raw,
532                arg4: *mut c_void,
533            ),
534        >,
535        user_data: *mut c_void,
536        codeloc: *mut c_void,
537    ) -> ffi_status;
538
539    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L441
540    #[cfg(not(target_arch = "x86"))]
541    #[deprecated = "Deprecated in libffi 3.3"]
542    pub fn ffi_prep_java_raw_closure(
543        arg1: *mut ffi_java_raw_closure,
544        cif: *mut ffi_cif,
545        fun: Option<
546            unsafe extern "C" fn(
547                arg1: *mut ffi_cif,
548                arg2: *mut c_void,
549                arg3: *mut ffi_java_raw,
550                arg4: *mut c_void,
551            ),
552        >,
553        user_data: *mut c_void,
554    ) -> ffi_status;
555
556    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L449
557    #[cfg(not(target_arch = "x86"))]
558    #[deprecated = "Deprecated in libffi 3.3"]
559    pub fn ffi_prep_java_raw_closure_loc(
560        arg1: *mut ffi_java_raw_closure,
561        cif: *mut ffi_cif,
562        fun: Option<
563            unsafe extern "C" fn(
564                arg1: *mut ffi_cif,
565                arg2: *mut c_void,
566                arg3: *mut ffi_java_raw,
567                arg4: *mut c_void,
568            ),
569        >,
570        user_data: *mut c_void,
571        codeloc: *mut c_void,
572    ) -> ffi_status;
573
574    pub fn ffi_prep_go_closure(
575        arg1: *mut ffi_go_closure,
576        arg2: *mut ffi_cif,
577        fun: Option<
578            unsafe extern "C" fn(
579                arg1: *mut ffi_cif,
580                arg2: *mut c_void,
581                arg3: *mut *mut c_void,
582                arg4: *mut c_void,
583            ),
584        >,
585    ) -> ffi_status;
586
587    pub fn ffi_call_go(
588        cif: *mut ffi_cif,
589        fn_: Option<unsafe extern "C" fn()>,
590        rvalue: *mut c_void,
591        avalue: *mut *mut c_void,
592        closure: *mut c_void,
593    );
594
595    pub fn ffi_prep_cif(
596        cif: *mut ffi_cif,
597        abi: ffi_abi,
598        nargs: c_uint,
599        rtype: *mut ffi_type,
600        atypes: *mut *mut ffi_type,
601    ) -> ffi_status;
602
603    pub fn ffi_prep_cif_var(
604        cif: *mut ffi_cif,
605        abi: ffi_abi,
606        nfixedargs: c_uint,
607        ntotalargs: c_uint,
608        rtype: *mut ffi_type,
609        atypes: *mut *mut ffi_type,
610    ) -> ffi_status;
611
612    pub fn ffi_call(
613        cif: *mut ffi_cif,
614        fn_: Option<unsafe extern "C" fn()>,
615        rvalue: *mut c_void,
616        avalue: *mut *mut c_void,
617    );
618
619    pub fn ffi_get_struct_offsets(
620        abi: ffi_abi,
621        struct_type: *mut ffi_type,
622        offsets: *mut usize,
623    ) -> ffi_status;
624}
625
626#[cfg(test)]
627mod test {
628    use std::{mem::transmute, ptr::addr_of_mut};
629
630    use super::*;
631
632    extern "C" fn cast_u8_u32(x: u8) -> u32 {
633        x as u32
634    }
635
636    #[test]
637    fn test_function_sign_extension() {
638        unsafe {
639            let mut cif: ffi_cif = Default::default();
640            let mut arg_types: Vec<*mut ffi_type> = vec![addr_of_mut!(ffi_type_uint8)];
641
642            let prep_status = ffi_prep_cif(
643                &mut cif,
644                ffi_abi_FFI_DEFAULT_ABI,
645                1,
646                addr_of_mut!(ffi_type_uint8),
647                arg_types.as_mut_ptr(),
648            );
649
650            assert_eq!(prep_status, ffi_status_FFI_OK);
651
652            let mut rval: ffi_arg = 0;
653            let func = transmute::<extern "C" fn(u8) -> u32, extern "C" fn()>(cast_u8_u32);
654
655            ffi_call(
656                &mut cif,
657                Some(func),
658                &mut rval as *mut _ as *mut c_void,
659                vec![&mut 256 as *mut _ as *mut c_void].as_mut_ptr(),
660            );
661
662            assert_eq!(rval, 0);
663        }
664    }
665
666    extern "C" fn add(x: u64, y: u64) -> u64 {
667        x + y
668    }
669
670    #[test]
671    fn test_function_with_two_arguments() {
672        unsafe {
673            let mut cif: ffi_cif = Default::default();
674            let mut arg_types: Vec<*mut ffi_type> =
675                vec![addr_of_mut!(ffi_type_uint64), addr_of_mut!(ffi_type_uint64)];
676
677            let prep_status = ffi_prep_cif(
678                &mut cif,
679                ffi_abi_FFI_DEFAULT_ABI,
680                2,
681                addr_of_mut!(ffi_type_uint64),
682                arg_types.as_mut_ptr(),
683            );
684
685            assert_eq!(prep_status, ffi_status_FFI_OK);
686
687            let mut rval = 0u64;
688            let func = transmute::<extern "C" fn(u64, u64) -> u64, extern "C" fn()>(add);
689
690            ffi_call(
691                &mut cif,
692                Some(func),
693                &mut rval as *mut _ as *mut c_void,
694                vec![
695                    &mut 4u64 as *mut _ as *mut c_void,
696                    &mut 5u64 as *mut _ as *mut c_void,
697                ]
698                .as_mut_ptr(),
699            );
700
701            assert_eq!(rval, 9);
702        }
703    }
704}