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&mut DebugStruct<'_, '_>.debug_struct("ffi_closure")
193 .field("tramp", unsafe { &&self.tramp.tramp[..] })
194 .field("cif", &self.cif)
195 .field("fun", &self.fun)
196 .field(name:"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: DebugStruct<'_, '_> = f.debug_struct(name:"ffi_raw_closure");
239 debug_struct
240 .field("tramp", &&self.tramp[..])
241 .field(name:"cif", &self.cif);
242
243 #[cfg(not(target_arch = "i686"))]
244 debug_struct.field(name:"translate_args", &self.translate_args);
245 #[cfg(not(target_arch = "i686"))]
246 debug_struct.field(name:"this_closure", &self.this_closure);
247
248 debug_struct&mut DebugStruct<'_, '_>
249 .field("fun", &self.fun)
250 .field(name:"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: DebugStruct<'_, '_> = f.debug_struct(name:"ffi_java_raw_closure");
292 debug_struct
293 .field("tramp", &&self.tramp[..])
294 .field(name:"cif", &self.cif);
295
296 #[cfg(not(target_arch = "i686"))]
297 debug_struct.field(name:"translate_args", &self.translate_args);
298 #[cfg(not(target_arch = "i686"))]
299 debug_struct.field(name:"this_closure", &self.this_closure);
300
301 debug_struct&mut DebugStruct<'_, '_>
302 .field("fun", &self.fun)
303 .field(name:"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}
589