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 | |
48 | use std::fmt::{self, Debug}; |
49 | use std::mem::zeroed; |
50 | use std::os::raw::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void}; |
51 | |
52 | mod arch; |
53 | pub use arch::*; |
54 | use fmt::Formatter; |
55 | |
56 | pub type ffi_arg = c_ulong; |
57 | pub type ffi_sarg = c_long; |
58 | pub type ffi_abi = u32; |
59 | pub type ffi_status = u32; |
60 | pub type ffi_type_enum = u32; |
61 | |
62 | pub const FFI_64_BIT_MAX: u64 = 9223372036854775807; |
63 | pub const FFI_CLOSURES: u32 = 1; |
64 | pub 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 |
66 | pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG; |
67 | |
68 | pub const FFI_TYPE_VOID: u32 = 0; |
69 | pub const FFI_TYPE_INT: u32 = 1; |
70 | pub const FFI_TYPE_FLOAT: u32 = 2; |
71 | pub const FFI_TYPE_DOUBLE: u32 = 3; |
72 | pub const FFI_TYPE_LONGDOUBLE: u32 = 4; |
73 | pub const FFI_TYPE_UINT8: u32 = 5; |
74 | pub const FFI_TYPE_SINT8: u32 = 6; |
75 | pub const FFI_TYPE_UINT16: u32 = 7; |
76 | pub const FFI_TYPE_SINT16: u32 = 8; |
77 | pub const FFI_TYPE_UINT32: u32 = 9; |
78 | pub const FFI_TYPE_SINT32: u32 = 10; |
79 | pub const FFI_TYPE_UINT64: u32 = 11; |
80 | pub const FFI_TYPE_SINT64: u32 = 12; |
81 | pub const FFI_TYPE_STRUCT: u32 = 13; |
82 | pub const FFI_TYPE_POINTER: u32 = 14; |
83 | pub const FFI_TYPE_COMPLEX: u32 = 15; |
84 | pub const FFI_TYPE_LAST: u32 = 15; |
85 | |
86 | pub const ffi_status_FFI_OK: ffi_status = 0; |
87 | pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1; |
88 | pub const ffi_status_FFI_BAD_ABI: ffi_status = 2; |
89 | pub const ffi_status_FFI_BAD_ARGTYPE: ffi_status = 3; |
90 | |
91 | pub const ffi_type_enum_STRUCT: ffi_type_enum = 13; |
92 | pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15; |
93 | |
94 | #[repr (C)] |
95 | #[derive (Debug, Copy, Clone)] |
96 | pub 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 | |
103 | impl Default for ffi_type { |
104 | fn default() -> Self { |
105 | unsafe { zeroed() } |
106 | } |
107 | } |
108 | |
109 | #[repr (C)] |
110 | #[derive (Debug, Copy, Clone)] |
111 | pub 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 | |
142 | impl Default for ffi_cif { |
143 | fn default() -> Self { |
144 | unsafe { zeroed() } |
145 | } |
146 | } |
147 | |
148 | #[repr (C, align(64))] |
149 | #[derive (Copy, Clone)] |
150 | pub 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 | |
158 | impl Default for ffi_raw { |
159 | fn default() -> Self { |
160 | unsafe { zeroed() } |
161 | } |
162 | } |
163 | |
164 | pub type ffi_java_raw = ffi_raw; |
165 | |
166 | #[repr (C, align(64))] |
167 | #[derive (Copy, Clone)] |
168 | pub 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)] |
175 | pub 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 |
190 | impl 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 | |
201 | impl Default for ffi_closure { |
202 | fn default() -> Self { |
203 | unsafe { zeroed() } |
204 | } |
205 | } |
206 | |
207 | #[repr (C)] |
208 | #[derive (Copy, Clone)] |
209 | pub 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 |
236 | impl 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 | |
255 | impl Default for ffi_raw_closure { |
256 | fn default() -> Self { |
257 | unsafe { zeroed() } |
258 | } |
259 | } |
260 | #[repr (C)] |
261 | #[derive (Copy, Clone)] |
262 | pub 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 |
289 | impl 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 | |
308 | impl Default for ffi_java_raw_closure { |
309 | fn default() -> Self { |
310 | unsafe { zeroed() } |
311 | } |
312 | } |
313 | |
314 | #[repr (C)] |
315 | #[derive (Debug, Copy, Clone)] |
316 | pub 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 | } |
328 | impl Default for ffi_go_closure { |
329 | fn default() -> Self { |
330 | unsafe { zeroed() } |
331 | } |
332 | } |
333 | |
334 | extern "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)] |
546 | mod 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 | |