libffi_sys2/
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    #[cfg(any(
141        target_arch = "mips",
142        target_arch = "mips32r6",
143        target_arch = "mips64",
144        target_arch = "mips64r6"
145    ))]
146    pub mips_nfixedargs: c_uint,
147}
148
149impl Default for ffi_cif {
150    fn default() -> Self {
151        unsafe { zeroed() }
152    }
153}
154
155#[repr(C, align(64))]
156#[derive(Copy, Clone)]
157pub union ffi_raw {
158    pub sint: ffi_sarg,
159    pub uint: ffi_arg,
160    pub flt: f32,
161    pub data: [c_char; FFI_SIZEOF_ARG],
162    pub ptr: *mut c_void,
163}
164
165impl Default for ffi_raw {
166    fn default() -> Self {
167        unsafe { zeroed() }
168    }
169}
170
171pub type ffi_java_raw = ffi_raw;
172
173#[repr(C, align(64))]
174#[derive(Copy, Clone)]
175pub union ffi_trampoline {
176    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
177    pub ftramp: *mut c_void,
178}
179
180#[repr(C)]
181#[derive(Copy, Clone)]
182pub struct ffi_closure {
183    pub tramp: ffi_trampoline,
184    pub cif: *mut ffi_cif,
185    pub fun: Option<
186        unsafe extern "C" fn(
187            arg1: *mut ffi_cif,
188            arg2: *mut c_void,
189            arg3: *mut *mut c_void,
190            arg4: *mut c_void,
191        ),
192    >,
193    pub user_data: *mut c_void,
194}
195
196/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
197impl Debug for ffi_closure {
198    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
199        f.debug_struct("ffi_closure")
200            .field("tramp", unsafe { &&self.tramp.tramp[..] })
201            .field("cif", &self.cif)
202            .field("fun", &self.fun)
203            .field("user_data", &self.user_data)
204            .finish()
205    }
206}
207
208impl Default for ffi_closure {
209    fn default() -> Self {
210        unsafe { zeroed() }
211    }
212}
213
214#[repr(C)]
215#[derive(Copy, Clone)]
216pub struct ffi_raw_closure {
217    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
218    pub cif: *mut ffi_cif,
219    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
220    #[cfg(not(target_arch = "i686"))]
221    pub translate_args: Option<
222        unsafe extern "C" fn(
223            arg1: *mut ffi_cif,
224            arg2: *mut c_void,
225            arg3: *mut *mut c_void,
226            arg4: *mut c_void,
227        ),
228    >,
229    #[cfg(not(target_arch = "i686"))]
230    pub this_closure: *mut c_void,
231    pub fun: Option<
232        unsafe extern "C" fn(
233            arg1: *mut ffi_cif,
234            arg2: *mut c_void,
235            arg3: *mut ffi_raw,
236            arg4: *mut c_void,
237        ),
238    >,
239    pub user_data: *mut c_void,
240}
241
242/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
243impl Debug for ffi_raw_closure {
244    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
245        let mut debug_struct = f.debug_struct("ffi_raw_closure");
246        debug_struct
247            .field("tramp", &&self.tramp[..])
248            .field("cif", &self.cif);
249
250        #[cfg(not(target_arch = "i686"))]
251        debug_struct.field("translate_args", &self.translate_args);
252        #[cfg(not(target_arch = "i686"))]
253        debug_struct.field("this_closure", &self.this_closure);
254
255        debug_struct
256            .field("fun", &self.fun)
257            .field("user_data", &self.user_data)
258            .finish()
259    }
260}
261
262impl Default for ffi_raw_closure {
263    fn default() -> Self {
264        unsafe { zeroed() }
265    }
266}
267#[repr(C)]
268#[derive(Copy, Clone)]
269pub struct ffi_java_raw_closure {
270    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
271    pub cif: *mut ffi_cif,
272    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L390
273    #[cfg(not(target_arch = "i686"))]
274    pub translate_args: Option<
275        unsafe extern "C" fn(
276            arg1: *mut ffi_cif,
277            arg2: *mut c_void,
278            arg3: *mut *mut c_void,
279            arg4: *mut c_void,
280        ),
281    >,
282    #[cfg(not(target_arch = "i686"))]
283    pub this_closure: *mut c_void,
284    pub fun: Option<
285        unsafe extern "C" fn(
286            arg1: *mut ffi_cif,
287            arg2: *mut c_void,
288            arg3: *mut ffi_java_raw,
289            arg4: *mut c_void,
290        ),
291    >,
292    pub user_data: *mut c_void,
293}
294
295/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
296impl Debug for ffi_java_raw_closure {
297    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
298        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
299        debug_struct
300            .field("tramp", &&self.tramp[..])
301            .field("cif", &self.cif);
302
303        #[cfg(not(target_arch = "i686"))]
304        debug_struct.field("translate_args", &self.translate_args);
305        #[cfg(not(target_arch = "i686"))]
306        debug_struct.field("this_closure", &self.this_closure);
307
308        debug_struct
309            .field("fun", &self.fun)
310            .field("user_data", &self.user_data)
311            .finish()
312    }
313}
314
315impl Default for ffi_java_raw_closure {
316    fn default() -> Self {
317        unsafe { zeroed() }
318    }
319}
320
321#[repr(C)]
322#[derive(Debug, Copy, Clone)]
323pub struct ffi_go_closure {
324    pub tramp: *mut c_void,
325    pub cif: *mut ffi_cif,
326    pub fun: Option<
327        unsafe extern "C" fn(
328            arg1: *mut ffi_cif,
329            arg2: *mut c_void,
330            arg3: *mut *mut c_void,
331            arg4: *mut c_void,
332        ),
333    >,
334}
335impl Default for ffi_go_closure {
336    fn default() -> Self {
337        unsafe { zeroed() }
338    }
339}
340
341extern "C" {
342    pub static mut ffi_type_void: ffi_type;
343    pub static mut ffi_type_uint8: ffi_type;
344    pub static mut ffi_type_sint8: ffi_type;
345    pub static mut ffi_type_uint16: ffi_type;
346    pub static mut ffi_type_sint16: ffi_type;
347    pub static mut ffi_type_uint32: ffi_type;
348    pub static mut ffi_type_sint32: ffi_type;
349    pub static mut ffi_type_uint64: ffi_type;
350    pub static mut ffi_type_sint64: ffi_type;
351    pub static mut ffi_type_float: ffi_type;
352    pub static mut ffi_type_double: ffi_type;
353    pub static mut ffi_type_pointer: ffi_type;
354
355    #[cfg(not(target_arch = "aarch64"))]
356    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
357    pub static mut ffi_type_longdouble: ffi_type;
358
359    #[cfg(feature = "complex")]
360    pub static mut ffi_type_complex_float: ffi_type;
361
362    #[cfg(feature = "complex")]
363    pub static mut ffi_type_complex_double: ffi_type;
364
365    #[cfg(feature = "complex")]
366    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
367    pub static mut ffi_type_complex_longdouble: ffi_type;
368
369    pub fn ffi_raw_call(
370        cif: *mut ffi_cif,
371        fn_: Option<unsafe extern "C" fn()>,
372        rvalue: *mut c_void,
373        avalue: *mut ffi_raw,
374    );
375
376    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
377
378    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
379
380    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
381
382    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L286
383    #[cfg(not(target_arch = "i686"))]
384    pub fn ffi_java_raw_call(
385        cif: *mut ffi_cif,
386        fn_: Option<unsafe extern "C" fn()>,
387        rvalue: *mut c_void,
388        avalue: *mut ffi_java_raw,
389    );
390
391    pub fn ffi_java_ptrarray_to_raw(
392        cif: *mut ffi_cif,
393        args: *mut *mut c_void,
394        raw: *mut ffi_java_raw,
395    );
396
397    pub fn ffi_java_raw_to_ptrarray(
398        cif: *mut ffi_cif,
399        raw: *mut ffi_java_raw,
400        args: *mut *mut c_void,
401    );
402
403    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
404
405    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
406
407    pub fn ffi_closure_free(arg1: *mut c_void);
408
409    pub fn ffi_prep_closure(
410        arg1: *mut ffi_closure,
411        arg2: *mut ffi_cif,
412        fun: Option<
413            unsafe extern "C" fn(
414                arg1: *mut ffi_cif,
415                arg2: *mut c_void,
416                arg3: *mut *mut c_void,
417                arg4: *mut c_void,
418            ),
419        >,
420        user_data: *mut c_void,
421    ) -> ffi_status;
422
423    pub fn ffi_prep_closure_loc(
424        arg1: *mut ffi_closure,
425        arg2: *mut ffi_cif,
426        fun: Option<
427            unsafe extern "C" fn(
428                arg1: *mut ffi_cif,
429                arg2: *mut c_void,
430                arg3: *mut *mut c_void,
431                arg4: *mut c_void,
432            ),
433        >,
434        user_data: *mut c_void,
435        codeloc: *mut c_void,
436    ) -> ffi_status;
437
438    pub fn ffi_prep_raw_closure(
439        arg1: *mut ffi_raw_closure,
440        cif: *mut ffi_cif,
441        fun: Option<
442            unsafe extern "C" fn(
443                arg1: *mut ffi_cif,
444                arg2: *mut c_void,
445                arg3: *mut ffi_raw,
446                arg4: *mut c_void,
447            ),
448        >,
449        user_data: *mut c_void,
450    ) -> ffi_status;
451
452    pub fn ffi_prep_raw_closure_loc(
453        arg1: *mut ffi_raw_closure,
454        cif: *mut ffi_cif,
455        fun: Option<
456            unsafe extern "C" fn(
457                arg1: *mut ffi_cif,
458                arg2: *mut c_void,
459                arg3: *mut ffi_raw,
460                arg4: *mut c_void,
461            ),
462        >,
463        user_data: *mut c_void,
464        codeloc: *mut c_void,
465    ) -> ffi_status;
466
467    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
468    #[cfg(not(target_arch = "i686"))]
469    pub fn ffi_prep_java_raw_closure(
470        arg1: *mut ffi_java_raw_closure,
471        cif: *mut ffi_cif,
472        fun: Option<
473            unsafe extern "C" fn(
474                arg1: *mut ffi_cif,
475                arg2: *mut c_void,
476                arg3: *mut ffi_java_raw,
477                arg4: *mut c_void,
478            ),
479        >,
480        user_data: *mut c_void,
481    ) -> ffi_status;
482
483    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
484    #[cfg(not(target_arch = "i686"))]
485    pub fn ffi_prep_java_raw_closure_loc(
486        arg1: *mut ffi_java_raw_closure,
487        cif: *mut ffi_cif,
488        fun: Option<
489            unsafe extern "C" fn(
490                arg1: *mut ffi_cif,
491                arg2: *mut c_void,
492                arg3: *mut ffi_java_raw,
493                arg4: *mut c_void,
494            ),
495        >,
496        user_data: *mut c_void,
497        codeloc: *mut c_void,
498    ) -> ffi_status;
499
500    pub fn ffi_prep_go_closure(
501        arg1: *mut ffi_go_closure,
502        arg2: *mut ffi_cif,
503        fun: Option<
504            unsafe extern "C" fn(
505                arg1: *mut ffi_cif,
506                arg2: *mut c_void,
507                arg3: *mut *mut c_void,
508                arg4: *mut c_void,
509            ),
510        >,
511    ) -> ffi_status;
512
513    pub fn ffi_call_go(
514        cif: *mut ffi_cif,
515        fn_: Option<unsafe extern "C" fn()>,
516        rvalue: *mut c_void,
517        avalue: *mut *mut c_void,
518        closure: *mut c_void,
519    );
520
521    pub fn ffi_prep_cif(
522        cif: *mut ffi_cif,
523        abi: ffi_abi,
524        nargs: c_uint,
525        rtype: *mut ffi_type,
526        atypes: *mut *mut ffi_type,
527    ) -> ffi_status;
528
529    pub fn ffi_prep_cif_var(
530        cif: *mut ffi_cif,
531        abi: ffi_abi,
532        nfixedargs: c_uint,
533        ntotalargs: c_uint,
534        rtype: *mut ffi_type,
535        atypes: *mut *mut ffi_type,
536    ) -> ffi_status;
537
538    pub fn ffi_call(
539        cif: *mut ffi_cif,
540        fn_: Option<unsafe extern "C" fn()>,
541        rvalue: *mut c_void,
542        avalue: *mut *mut c_void,
543    );
544
545    pub fn ffi_get_struct_offsets(
546        abi: ffi_abi,
547        struct_type: *mut ffi_type,
548        offsets: *mut usize,
549    ) -> ffi_status;
550}
551
552#[cfg(test)]
553mod test {
554    use super::*;
555
556    extern "C" fn add(x: u64, y: u64) -> u64 {
557        x + y
558    }
559
560    #[test]
561    fn test_function_with_two_arguments() {
562        unsafe {
563            let mut cif: ffi_cif = Default::default();
564            let mut arg_types: Vec<*mut ffi_type> =
565                vec![&mut ffi_type_uint64, &mut ffi_type_uint64];
566
567            let prep_status = ffi_prep_cif(
568                &mut cif,
569                ffi_abi_FFI_DEFAULT_ABI,
570                2,
571                &mut ffi_type_uint64,
572                arg_types.as_mut_ptr(),
573            );
574
575            assert_eq!(prep_status, ffi_status_FFI_OK);
576
577            let mut rval = 0u64;
578            let func = &*(&(add as *mut extern "C" fn(u64, u64) -> u64) as *const _
579                as *const extern "C" fn());
580
581            ffi_call(
582                &mut cif,
583                Some(*func),
584                &mut rval as *mut _ as *mut c_void,
585                vec![
586                    &mut 4u64 as *mut _ as *mut c_void,
587                    &mut 5u64 as *mut _ as *mut c_void,
588                ]
589                .as_mut_ptr(),
590            );
591
592            assert_eq!(rval, 9);
593        }
594    }
595}