libffi_sys/
lib.rs

1#![doc(html_root_url = "https://docs.rs/libffi-sys/2.3.0")]
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 an 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
19//! ship with an old C libffi; this requires that you have a working make,
20//! C compiler, automake, and autoconf first. If your system libffi
21//! is new enough (v3.2.1 as of October 2019), you can instead enable the
22//! `system` feature flag to use that. If you want this crate to build
23//! a C libffi for you, add
24//!
25//! ```toml
26//! [dependencies]
27//! libffi-sys = "2.3.0"
28//! ```
29//!
30//! to your `Cargo.toml`. If you want to use your system C libffi, then
31//!
32//! ```toml
33//! [dependencies.libffi-sys]
34//! version = "2.3.0"
35//! features = ["system"]
36//! ```
37//!
38//! to your `Cargo.toml` instead.
39//!
40//! This crate supports Rust version 1.32 and later.
41
42#![allow(non_camel_case_types)]
43#![allow(non_snake_case)]
44#![allow(non_upper_case_globals)]
45#![allow(improper_ctypes)]
46#![allow(unused_imports)]
47
48use std::fmt::{self, Debug};
49use std::mem::zeroed;
50use std::os::raw::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void};
51
52mod arch;
53pub use arch::*;
54use fmt::Formatter;
55
56pub type ffi_arg = c_ulong;
57pub type ffi_sarg = c_long;
58pub type ffi_abi = u32;
59pub type ffi_status = u32;
60pub type ffi_type_enum = u32;
61
62pub const FFI_64_BIT_MAX: u64 = 9223372036854775807;
63pub const FFI_CLOSURES: u32 = 1;
64pub const FFI_SIZEOF_ARG: usize = std::mem::size_of::<c_long>();
65// NOTE: This only differs from FFI_SIZEOF_ARG on ILP platforms, which Rust does not support
66pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG;
67
68pub const FFI_TYPE_VOID: u32 = 0;
69pub const FFI_TYPE_INT: u32 = 1;
70pub const FFI_TYPE_FLOAT: u32 = 2;
71pub const FFI_TYPE_DOUBLE: u32 = 3;
72pub const FFI_TYPE_LONGDOUBLE: u32 = 4;
73pub const FFI_TYPE_UINT8: u32 = 5;
74pub const FFI_TYPE_SINT8: u32 = 6;
75pub const FFI_TYPE_UINT16: u32 = 7;
76pub const FFI_TYPE_SINT16: u32 = 8;
77pub const FFI_TYPE_UINT32: u32 = 9;
78pub const FFI_TYPE_SINT32: u32 = 10;
79pub const FFI_TYPE_UINT64: u32 = 11;
80pub const FFI_TYPE_SINT64: u32 = 12;
81pub const FFI_TYPE_STRUCT: u32 = 13;
82pub const FFI_TYPE_POINTER: u32 = 14;
83pub const FFI_TYPE_COMPLEX: u32 = 15;
84pub const FFI_TYPE_LAST: u32 = 15;
85
86pub const ffi_status_FFI_OK: ffi_status = 0;
87pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1;
88pub const ffi_status_FFI_BAD_ABI: ffi_status = 2;
89pub const ffi_status_FFI_BAD_ARGTYPE: ffi_status = 3;
90
91pub const ffi_type_enum_STRUCT: ffi_type_enum = 13;
92pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15;
93
94#[repr(C)]
95#[derive(Debug, Copy, Clone)]
96pub struct ffi_type {
97    pub size: usize,
98    pub alignment: c_ushort,
99    pub type_: c_ushort,
100    pub elements: *mut *mut ffi_type,
101}
102
103impl Default for ffi_type {
104    fn default() -> Self {
105        unsafe { zeroed() }
106    }
107}
108
109#[repr(C)]
110#[derive(Debug, Copy, Clone)]
111pub struct ffi_cif {
112    pub abi: ffi_abi,
113    pub nargs: c_uint,
114    pub arg_types: *mut *mut ffi_type,
115    pub rtype: *mut ffi_type,
116    pub bytes: c_uint,
117    pub flags: c_uint,
118    #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
119    pub is_variadic: c_uint,
120    #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
121    pub aarch64_nfixedargs: c_uint,
122    #[cfg(all(target_arch = "arm"))]
123    pub vfp_used: c_int,
124    #[cfg(all(target_arch = "arm"))]
125    pub vfp_reg_free: c_ushort,
126    #[cfg(all(target_arch = "arm"))]
127    pub vfp_nargs: c_ushort,
128    #[cfg(all(target_arch = "arm"))]
129    pub vfp_args: [c_schar; 16],
130    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
131    pub nfixedargs: c_uint,
132    #[cfg(any(target_arch = "riscv", target_arch = "riscv64"))]
133    pub riscv_nfixedargs: c_uint,
134    #[cfg(any(target_arch = "riscv", target_arch = "riscv64"))]
135    pub riscv_unused: c_uint,
136    #[cfg(all(target_arch = "loongarch64"))]
137    pub loongarch_nfixedargs: c_uint,
138    #[cfg(all(target_arch = "loongarch64"))]
139    pub loongarch_unused: c_uint,
140}
141
142impl Default for ffi_cif {
143    fn default() -> Self {
144        unsafe { zeroed() }
145    }
146}
147
148#[repr(C, align(64))]
149#[derive(Copy, Clone)]
150pub union ffi_raw {
151    pub sint: ffi_sarg,
152    pub uint: ffi_arg,
153    pub flt: f32,
154    pub data: [c_char; FFI_SIZEOF_ARG],
155    pub ptr: *mut c_void,
156}
157
158impl Default for ffi_raw {
159    fn default() -> Self {
160        unsafe { zeroed() }
161    }
162}
163
164pub type ffi_java_raw = ffi_raw;
165
166#[repr(C, align(64))]
167#[derive(Copy, Clone)]
168pub union ffi_trampoline {
169    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
170    pub ftramp: *mut c_void,
171}
172
173#[repr(C)]
174#[derive(Copy, Clone)]
175pub struct ffi_closure {
176    pub tramp: ffi_trampoline,
177    pub cif: *mut ffi_cif,
178    pub fun: Option<
179        unsafe extern "C" fn(
180            arg1: *mut ffi_cif,
181            arg2: *mut c_void,
182            arg3: *mut *mut c_void,
183            arg4: *mut c_void,
184        ),
185    >,
186    pub user_data: *mut c_void,
187}
188
189/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
190impl Debug for ffi_closure {
191    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
192        f.debug_struct("ffi_closure")
193            .field("tramp", unsafe { &&self.tramp.tramp[..] })
194            .field("cif", &self.cif)
195            .field("fun", &self.fun)
196            .field("user_data", &self.user_data)
197            .finish()
198    }
199}
200
201impl Default for ffi_closure {
202    fn default() -> Self {
203        unsafe { zeroed() }
204    }
205}
206
207#[repr(C)]
208#[derive(Copy, Clone)]
209pub struct ffi_raw_closure {
210    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
211    pub cif: *mut ffi_cif,
212    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
213    #[cfg(not(target_arch = "i686"))]
214    pub translate_args: Option<
215        unsafe extern "C" fn(
216            arg1: *mut ffi_cif,
217            arg2: *mut c_void,
218            arg3: *mut *mut c_void,
219            arg4: *mut c_void,
220        ),
221    >,
222    #[cfg(not(target_arch = "i686"))]
223    pub this_closure: *mut c_void,
224    pub fun: Option<
225        unsafe extern "C" fn(
226            arg1: *mut ffi_cif,
227            arg2: *mut c_void,
228            arg3: *mut ffi_raw,
229            arg4: *mut c_void,
230        ),
231    >,
232    pub user_data: *mut c_void,
233}
234
235/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
236impl Debug for ffi_raw_closure {
237    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
238        let mut debug_struct = f.debug_struct("ffi_raw_closure");
239        debug_struct
240            .field("tramp", &&self.tramp[..])
241            .field("cif", &self.cif);
242
243        #[cfg(not(target_arch = "i686"))]
244        debug_struct.field("translate_args", &self.translate_args);
245        #[cfg(not(target_arch = "i686"))]
246        debug_struct.field("this_closure", &self.this_closure);
247
248        debug_struct
249            .field("fun", &self.fun)
250            .field("user_data", &self.user_data)
251            .finish()
252    }
253}
254
255impl Default for ffi_raw_closure {
256    fn default() -> Self {
257        unsafe { zeroed() }
258    }
259}
260#[repr(C)]
261#[derive(Copy, Clone)]
262pub struct ffi_java_raw_closure {
263    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
264    pub cif: *mut ffi_cif,
265    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L390
266    #[cfg(not(target_arch = "i686"))]
267    pub translate_args: Option<
268        unsafe extern "C" fn(
269            arg1: *mut ffi_cif,
270            arg2: *mut c_void,
271            arg3: *mut *mut c_void,
272            arg4: *mut c_void,
273        ),
274    >,
275    #[cfg(not(target_arch = "i686"))]
276    pub this_closure: *mut c_void,
277    pub fun: Option<
278        unsafe extern "C" fn(
279            arg1: *mut ffi_cif,
280            arg2: *mut c_void,
281            arg3: *mut ffi_java_raw,
282            arg4: *mut c_void,
283        ),
284    >,
285    pub user_data: *mut c_void,
286}
287
288/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
289impl Debug for ffi_java_raw_closure {
290    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
291        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
292        debug_struct
293            .field("tramp", &&self.tramp[..])
294            .field("cif", &self.cif);
295
296        #[cfg(not(target_arch = "i686"))]
297        debug_struct.field("translate_args", &self.translate_args);
298        #[cfg(not(target_arch = "i686"))]
299        debug_struct.field("this_closure", &self.this_closure);
300
301        debug_struct
302            .field("fun", &self.fun)
303            .field("user_data", &self.user_data)
304            .finish()
305    }
306}
307
308impl Default for ffi_java_raw_closure {
309    fn default() -> Self {
310        unsafe { zeroed() }
311    }
312}
313
314#[repr(C)]
315#[derive(Debug, Copy, Clone)]
316pub struct ffi_go_closure {
317    pub tramp: *mut c_void,
318    pub cif: *mut ffi_cif,
319    pub fun: Option<
320        unsafe extern "C" fn(
321            arg1: *mut ffi_cif,
322            arg2: *mut c_void,
323            arg3: *mut *mut c_void,
324            arg4: *mut c_void,
325        ),
326    >,
327}
328impl Default for ffi_go_closure {
329    fn default() -> Self {
330        unsafe { zeroed() }
331    }
332}
333
334extern "C" {
335    pub static mut ffi_type_void: ffi_type;
336    pub static mut ffi_type_uint8: ffi_type;
337    pub static mut ffi_type_sint8: ffi_type;
338    pub static mut ffi_type_uint16: ffi_type;
339    pub static mut ffi_type_sint16: ffi_type;
340    pub static mut ffi_type_uint32: ffi_type;
341    pub static mut ffi_type_sint32: ffi_type;
342    pub static mut ffi_type_uint64: ffi_type;
343    pub static mut ffi_type_sint64: ffi_type;
344    pub static mut ffi_type_float: ffi_type;
345    pub static mut ffi_type_double: ffi_type;
346    pub static mut ffi_type_pointer: ffi_type;
347
348    #[cfg(not(target_arch = "aarch64"))]
349    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
350    pub static mut ffi_type_longdouble: ffi_type;
351
352    #[cfg(feature = "complex")]
353    pub static mut ffi_type_complex_float: ffi_type;
354
355    #[cfg(feature = "complex")]
356    pub static mut ffi_type_complex_double: ffi_type;
357
358    #[cfg(feature = "complex")]
359    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
360    pub static mut ffi_type_complex_longdouble: ffi_type;
361
362    pub fn ffi_raw_call(
363        cif: *mut ffi_cif,
364        fn_: Option<unsafe extern "C" fn()>,
365        rvalue: *mut c_void,
366        avalue: *mut ffi_raw,
367    );
368
369    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
370
371    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
372
373    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
374
375    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L286
376    #[cfg(not(target_arch = "i686"))]
377    pub fn ffi_java_raw_call(
378        cif: *mut ffi_cif,
379        fn_: Option<unsafe extern "C" fn()>,
380        rvalue: *mut c_void,
381        avalue: *mut ffi_java_raw,
382    );
383
384    pub fn ffi_java_ptrarray_to_raw(
385        cif: *mut ffi_cif,
386        args: *mut *mut c_void,
387        raw: *mut ffi_java_raw,
388    );
389
390    pub fn ffi_java_raw_to_ptrarray(
391        cif: *mut ffi_cif,
392        raw: *mut ffi_java_raw,
393        args: *mut *mut c_void,
394    );
395
396    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
397
398    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
399
400    pub fn ffi_closure_free(arg1: *mut c_void);
401
402    pub fn ffi_prep_closure(
403        arg1: *mut ffi_closure,
404        arg2: *mut ffi_cif,
405        fun: Option<
406            unsafe extern "C" fn(
407                arg1: *mut ffi_cif,
408                arg2: *mut c_void,
409                arg3: *mut *mut c_void,
410                arg4: *mut c_void,
411            ),
412        >,
413        user_data: *mut c_void,
414    ) -> ffi_status;
415
416    pub fn ffi_prep_closure_loc(
417        arg1: *mut ffi_closure,
418        arg2: *mut ffi_cif,
419        fun: Option<
420            unsafe extern "C" fn(
421                arg1: *mut ffi_cif,
422                arg2: *mut c_void,
423                arg3: *mut *mut c_void,
424                arg4: *mut c_void,
425            ),
426        >,
427        user_data: *mut c_void,
428        codeloc: *mut c_void,
429    ) -> ffi_status;
430
431    pub fn ffi_prep_raw_closure(
432        arg1: *mut ffi_raw_closure,
433        cif: *mut ffi_cif,
434        fun: Option<
435            unsafe extern "C" fn(
436                arg1: *mut ffi_cif,
437                arg2: *mut c_void,
438                arg3: *mut ffi_raw,
439                arg4: *mut c_void,
440            ),
441        >,
442        user_data: *mut c_void,
443    ) -> ffi_status;
444
445    pub fn ffi_prep_raw_closure_loc(
446        arg1: *mut ffi_raw_closure,
447        cif: *mut ffi_cif,
448        fun: Option<
449            unsafe extern "C" fn(
450                arg1: *mut ffi_cif,
451                arg2: *mut c_void,
452                arg3: *mut ffi_raw,
453                arg4: *mut c_void,
454            ),
455        >,
456        user_data: *mut c_void,
457        codeloc: *mut c_void,
458    ) -> ffi_status;
459
460    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
461    #[cfg(not(target_arch = "i686"))]
462    pub fn ffi_prep_java_raw_closure(
463        arg1: *mut ffi_java_raw_closure,
464        cif: *mut ffi_cif,
465        fun: Option<
466            unsafe extern "C" fn(
467                arg1: *mut ffi_cif,
468                arg2: *mut c_void,
469                arg3: *mut ffi_java_raw,
470                arg4: *mut c_void,
471            ),
472        >,
473        user_data: *mut c_void,
474    ) -> ffi_status;
475
476    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
477    #[cfg(not(target_arch = "i686"))]
478    pub fn ffi_prep_java_raw_closure_loc(
479        arg1: *mut ffi_java_raw_closure,
480        cif: *mut ffi_cif,
481        fun: Option<
482            unsafe extern "C" fn(
483                arg1: *mut ffi_cif,
484                arg2: *mut c_void,
485                arg3: *mut ffi_java_raw,
486                arg4: *mut c_void,
487            ),
488        >,
489        user_data: *mut c_void,
490        codeloc: *mut c_void,
491    ) -> ffi_status;
492
493    pub fn ffi_prep_go_closure(
494        arg1: *mut ffi_go_closure,
495        arg2: *mut ffi_cif,
496        fun: Option<
497            unsafe extern "C" fn(
498                arg1: *mut ffi_cif,
499                arg2: *mut c_void,
500                arg3: *mut *mut c_void,
501                arg4: *mut c_void,
502            ),
503        >,
504    ) -> ffi_status;
505
506    pub fn ffi_call_go(
507        cif: *mut ffi_cif,
508        fn_: Option<unsafe extern "C" fn()>,
509        rvalue: *mut c_void,
510        avalue: *mut *mut c_void,
511        closure: *mut c_void,
512    );
513
514    pub fn ffi_prep_cif(
515        cif: *mut ffi_cif,
516        abi: ffi_abi,
517        nargs: c_uint,
518        rtype: *mut ffi_type,
519        atypes: *mut *mut ffi_type,
520    ) -> ffi_status;
521
522    pub fn ffi_prep_cif_var(
523        cif: *mut ffi_cif,
524        abi: ffi_abi,
525        nfixedargs: c_uint,
526        ntotalargs: c_uint,
527        rtype: *mut ffi_type,
528        atypes: *mut *mut ffi_type,
529    ) -> ffi_status;
530
531    pub fn ffi_call(
532        cif: *mut ffi_cif,
533        fn_: Option<unsafe extern "C" fn()>,
534        rvalue: *mut c_void,
535        avalue: *mut *mut c_void,
536    );
537
538    pub fn ffi_get_struct_offsets(
539        abi: ffi_abi,
540        struct_type: *mut ffi_type,
541        offsets: *mut usize,
542    ) -> ffi_status;
543}
544
545#[cfg(test)]
546mod test {
547    use super::*;
548
549    extern "C" fn add(x: u64, y: u64) -> u64 {
550        x + y
551    }
552
553    #[test]
554    fn test_function_with_two_arguments() {
555        unsafe {
556            let mut cif: ffi_cif = Default::default();
557            let mut arg_types: Vec<*mut ffi_type> =
558                vec![&mut ffi_type_uint64, &mut ffi_type_uint64];
559
560            let prep_status = ffi_prep_cif(
561                &mut cif,
562                ffi_abi_FFI_DEFAULT_ABI,
563                2,
564                &mut ffi_type_uint64,
565                arg_types.as_mut_ptr(),
566            );
567
568            assert_eq!(prep_status, ffi_status_FFI_OK);
569
570            let mut rval = 0u64;
571            let func = &*(&(add as *mut extern "C" fn(u64, u64) -> u64) as *const _
572                as *const extern "C" fn());
573
574            ffi_call(
575                &mut cif,
576                Some(*func),
577                &mut rval as *mut _ as *mut c_void,
578                vec![
579                    &mut 4u64 as *mut _ as *mut c_void,
580                    &mut 5u64 as *mut _ as *mut c_void,
581                ]
582                .as_mut_ptr(),
583            );
584
585            assert_eq!(rval, 9);
586        }
587    }
588}