summaryrefslogtreecommitdiffstats
path: root/arith.h
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-28 05:31:26 +0000
committerKaz Kylheku <kaz@kylheku.com>2017-05-28 05:31:26 +0000
commit10507446389cff9b072c25aa86ba35834a786fe5 (patch)
tree0b01a0f741407278b005952ce1ec4f5a8b9c399e /arith.h
parent194297377d00935a4d5df2d162871b0da930f1d5 (diff)
downloadtxr-10507446389cff9b072c25aa86ba35834a786fe5.tar.gz
txr-10507446389cff9b072c25aa86ba35834a786fe5.tar.bz2
txr-10507446389cff9b072c25aa86ba35834a786fe5.zip
ffi: adapt to return value braindamage in libffi.
This change gets TXR FFI working on Power PC 64, big endian. Many thanks to the GCC Compile Farm. Turns out, the libffi API has changed some years ago, with outdated documentation lingering. Return values for the basic integral types must all be handled with a buffer of type ffi_arg and casting. This is true in both ffi_call and closures: in both directions. For instance, if a foreign function returns char, we must retrieve a ffi_arg value (which might be as large as 64 bits). Then we must cast this value to char. In actual fact, on a big endian system with an 8 byte ffi_arg, the char value may be located in byte 7 of the 8 byte buffer, not in byte 0. FFI's own test suite got this wrong and had to be patched back in 2013: it was doing things the way we are doing them: https://sourceware.org/ml/libffi-discuss/2013/msg00199.html The doc was updated at the same time to tell the truth: https://sourceware.org/ml/libffi-discuss/2013/msg00200.html Luckily, we can fix TXR's ffi module without damaging its framework. The object model is flexible enough to absorb the change. Basically, we add two new methods to the txr_ffi_type objects: virtual functions rget and rput. We only add these when targetting big endian. These have the same type signature as get and put, but are specialized for handling return values. For all integer types smaller than 64 bits, these functions are separately implemented with distinct semanics which handle the FFI API requirements with ffi_arg and casting and all. For all other types, rget and rput are identical to get and put. * ffi.c (pad_retval, ifbe, ifbe2): New macros, conditionally defined for big and little endian. (struct txr_ffi_type): New members rput and rget. (ffi_i8_rput, ffi_i8_rget, ffi_u8_rput, ffi_u8_rget, ffi_i16_rput, ffi_i16_rget, ffi_u16_rput, ffi_u16_rget, ffi_i32_rput, ffi_i32_rget, ffi_u32_rput, ffi_u32_rget, ffi_char_rput, ffi_char_rget, ffi_uchar_rput, ffi_uchar_rget, ffi_bchar_rget, ffi_short_rput, ffi_short_rget, ffi_ushort_rput, ffi_ushort_rget, ffi_int_rput, ffi_int_rget, ffi_uint_rput, ffi_uint_rget, ffi_long_rput, ffi_long_rget, ffi_ulong_rput, ffi_ulong_rget, ffi_wchar_rput): New functions. (make_ffi_type_builtin): Take rput and rget arguments, regardless of platform. On big endian, store these in the corresponding members. If they are null, duplicate get and put instead. (ffi_type_compile, ffi_init_types): Specify the rput and rget functions for the basic types, using the ifbe macro which nullifies the references to functions when they don't exist on little endian. For all other types, pass the new arguments as null. (ffi_call_wrap): Pad the return vaue buffer size to a minimum size on big endian; it must be at least sizeof (ffi_alloc). Use the rget method for the return value on big endian. (ffi_closure_dispatch, ffi_closure_dispatch_safe): Use rput on big endian for storing return value.
Diffstat (limited to 'arith.h')
0 files changed, 0 insertions, 0 deletions