This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
Re: documentation patch, oddities, and proposals
- From: Andrew Pinski <pinskia at gcc dot gnu dot org>
- To: Tom Tromey <tom at tromey dot com>
- Cc: libffi-discuss <libffi-discuss at sourceware dot org>
- Date: Wed, 4 Nov 2015 13:35:10 +0800
- Subject: Re: documentation patch, oddities, and proposals
- Authentication-results: sourceware.org; auth=none
- References: <87d1vqe3e0 dot fsf at tromey dot com>
On Wed, Nov 4, 2015 at 1:32 PM, Tom Tromey <tom@tromey.com> wrote:
> Hi!
>
> [ I tried to send this once before but I don't know that it went
> through, so trying again... ]
>
> I've been working on an FFI:
>
> https://github.com/tromey/emacs-ffi
>
> While doing so I refreshed my memory of some of the oddities of libffi,
> and discovered some I had never run across before.
>
> I found a few things that weren't documented. I wrote a documentation
> patch that I think covers them all. It is appended. If you like it I
> can write a ChangeLog entry and submit a pull request.
>
> Some questions, observations, and proposals:
>
> * The ffi_arg business for return values I (re-)learned from reading the
> archvies. I still haven't fixed my own code to deal with this yet.
>
> I wasn't sure -- is this needed in some way for the closure API as
> well? If so, and someone can explain where (that is, arguments,
> return values, or both), I will write a documentation patch.
>
> * I wanted to compute the layout of a struct. libffi does this
> internally but doesn't expose the results.
>
> I think it would be great to have a new function to do this. In fact
> I wrote one, but...
Yes this would be useful as it would be nice to move libobjc away from
its current mess of using GCC's internal headers too.
Thanks,
Andrew
>
> * ... this lead me to the discovery that ffi_prep_types modifies some of
> the libffi globals, meaning that libffi is not type-safe when using
> multiple ABIs.
>
> Currently, AFAICT, this only affects long doubles on PPC. So, not
> quite as bad as it seems -- but still it is a bug.
>
> * Also due to ffi_prep_types, you can't really use the size and
> alignment fields of an ffi_type unless you know that the ABI hasn't
> changed. And, because of this, you also can't share structure types
> across ABIs. (Maybe that is obvious? It was a bit of a surprise to
> me.)
>
> * As you can see from the docs, I also had to resort to some shenanigans
> to get arrays and unions working. I think it would be preferable to
> have FFI_TYPE_ARRAY and FFI_TYPE_UNION directly in the library.
>
> * This doesn't impact the docs, but ffi.h.in is a mix of public and
> private stuff. I think it would be nice to separate these.
>
> * I didn't write docs for the raw or java APIs. It's probably time for
> those to die.
>
> * Someone who understands what it does should perhaps write
> documentation for the Go closure code. Or, if this is only for use by
> gccgo, then maybe it should be relegated to the aforementioned
> internal-only header.
>
> Tom
>
> diff --git a/doc/libffi.texi b/doc/libffi.texi
> index ff72e58..16c1b53 100644
> --- a/doc/libffi.texi
> +++ b/doc/libffi.texi
> @@ -107,6 +107,7 @@ values passed between the two languages.
> * Multiple ABIs:: Different passing styles on one platform.
> * The Closure API:: Writing a generic function.
> * Closure Example:: A closure example.
> +* Thread Safety:: Thread safety.
> @end menu
>
>
> @@ -190,12 +191,23 @@ to ensure this. If @var{cif} declares that the function returns
> @code{void} (using @code{ffi_type_void}), then @var{rvalue} is
> ignored.
>
> +For types like @code{char} that are narrower than the system register
> +size, @samp{libffi} provides a type, @code{ffi_arg}, that can be used
> +as the return type.
> +
> @var{avalues} is a vector of @code{void *} pointers that point to the
> memory locations holding the argument values for a call. If @var{cif}
> declares that the function has no arguments (i.e., @var{nargs} was 0),
> then @var{avalues} is ignored. Note that argument values may be
> modified by the callee (for instance, structs passed by value); the
> burden of copying pass-by-value arguments is placed on the caller.
> +
> +Note that while the return value must be register-sized, arguments
> +should exactly match their declared type. For example, if an argument
> +is a @code{short}, then the entry is @var{avalues} should point to an
> +object declared as @code{short}; but if the return type is
> +@code{short}, then @var{rvalue} should point to an object declared as
> +a larger type -- usually @code{ffi_arg}.
> @end defun
>
>
> @@ -246,6 +258,8 @@ int main()
> @menu
> * Primitive Types:: Built-in types.
> * Structures:: Structure types.
> +* Size and Alignment:: Size and alignment of types.
> +* Arrays and Unions:: Arrays and unions.
> * Type Example:: Structure type example.
> * Complex:: Complex types.
> * Complex Type Example:: Complex type example.
> @@ -370,8 +384,7 @@ when passing to @code{ffi_prep_cif}.
> @node Structures
> @subsection Structures
>
> -Although @samp{libffi} has no special support for unions or
> -bit-fields, it is perfectly happy passing structures back and forth.
> +@samp{libffi} is perfectly happy passing structures back and forth.
> You must first describe the structure to @samp{libffi} by creating a
> new @code{ffi_type} object for it.
>
> @@ -391,9 +404,132 @@ For a structure, this should be set to @code{FFI_TYPE_STRUCT}.
> @item ffi_type **elements
> This is a @samp{NULL}-terminated array of pointers to @code{ffi_type}
> objects. There is one element per field of the struct.
> +
> +Note that @samp{libffi} has no special support for bit-fields. You
> +must manage these manually.
> @end table
> @end deftp
>
> +The @code{size} and @code{alignment} fields will be filled in by
> +@code{ffi_prep_cif} or @code{ffi_prep_cif_var}, as needed.
> +
> +@node Size and Alignment
> +@subsection Size and Alignment
> +
> +@code{libffi} will set the @code{size} and @code{alignment} fields of
> +an @code{ffi_type} object for you. It does so using its knowledge of
> +the ABI.
> +
> +You might expect that you can simply read these fields for a type that
> +has been laid out by @code{libffi}. However, there are some caveats.
> +
> +@itemize @bullet
> +@item
> +The size or alignment of some of the built-in types may vary depending
> +on the chosen ABI.
> +
> +@item
> +The size and alignment of a new structure type will not be set by
> +@code{libffi} until it has been passed to @code{ffi_prep_cif}.
> +
> +@item
> +A structure type cannot be shared across ABIs. Instead each ABI needs
> +its own copy of the structure type.
> +@end itemize
> +
> +So, before examining these fields, it is safest to pass the
> +@code{ffi_type} object to @code{ffi_prep_cif} first. This function
> +will do all the needed setup.
> +
> +@example
> +ffi_type *desired_type;
> +ffi_abi desired_abi;
> +...
> +ffi_cif cif;
> +if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK)
> + @{
> + size_t size = desired_type->size;
> + unsigned short alignment = desired_type->alignment;
> + @}
> +@end example
> +
> +@node Arrays and Unions
> +@subsection Arrays and Unions
> +
> +@subsubsection Arrays
> +
> +@samp{libffi} does not have direct support for arrays or unions.
> +However, they can be emulated using structures.
> +
> +To emulate an array, simply create an @code{ffi_type} using
> +@code{FFI_TYPE_STRUCT} with as many members as there are elements in
> +the array.
> +
> +@example
> +ffi_type array_type;
> +ffi_type **elements
> +int i;
> +
> +elements = malloc ((n + 1) * sizeof (ffi_type *));
> +for (i = 0; i < n; ++i)
> + elements[i] = array_element_type;
> +elements[n] = NULL;
> +
> +array_type.size = array_type.alignment = 0;
> +array_type.type = FFI_TYPE_STRUCT;
> +array_type.elements = elements;
> +@end example
> +
> +Note that arrays cannot be passed or returned by value in C --
> +structure types created like this should only be used to refer to
> +members of real @code{FFI_TYPE_STRUCT} objects.
> +
> +However, a phony array type like this will not cause any errors from
> +@samp{libffi} if you use it as an argument or return type. This may
> +be confusing.
> +
> +@subsubsection Unions
> +
> +A union can also be emulated using @code{FFI_TYPE_STRUCT}. In this
> +case, however, you must make sure that the size and alignment match
> +the real requirements of the union.
> +
> +One simple way to do this is to ensue that each element type is laid
> +out. Then, give the new structure type a single element; the size of
> +the largest element; and the largest alignment seen as well.
> +
> +This example uses the @code{ffi_prep_cif} trick to ensure that each
> +element type is laid out.
> +
> +@example
> +ffi_abi desired_abi;
> +ffi_type union_type;
> +ffi_type **union_elements;
> +
> +int i;
> +ffi_type element_types[2];
> +
> +element_types[1] = NULL;
> +
> +union_type.size = union_type.alignment = 0;
> +union_type.type = FFI_TYPE_STRUCT;
> +union_type.elements = element_types;
> +
> +for (i = 0; union_elements[i]; ++i)
> + @{
> + ffi_cif cif;
> + if (ffi_prep_cif (&cif, desired_abi, 0, union_elements[i], NULL) == FFI_OK)
> + @{
> + if (union_elements[i]->size > union_type.size)
> + @{
> + union_type.size = union_elements[i];
> + size = union_elements[i]->size;
> + @}
> + if (union_elements[i]->alignment > union_type.alignment)
> + union_type.alignment = union_elements[i]->alignment;
> + @}
> + @}
> +@end example
>
> @node Type Example
> @subsection Type Example
> @@ -636,6 +772,8 @@ Prepare a closure function.
> the writable address returned by @code{ffi_closure_alloc}.
>
> @var{cif} is the @code{ffi_cif} describing the function parameters.
> +Note that this object, and the types to which it refers, must be kept
> +alive until the closure itself is freed.
>
> @var{user_data} is an arbitrary datum that is passed, uninterpreted,
> to your closure function.
> @@ -733,6 +871,28 @@ int main()
>
> @end example
>
> +@node Thread Safety
> +@section Thread Safety
> +
> +@code{libffi} is not completely thread-safe. However, many parts are,
> +and if you follow some simple rules, you can use it safely in a
> +multi-threaded program.
> +
> +@itemize @bullet
> +@item
> +@code{ffi_prep_cif} may modify the @code{ffi_type} objects passed to
> +it. It is best to ensure that only a single thread prepares a given
> +@code{ffi_cif} at a time.
> +
> +@item
> +On some platforms, @code{ffi_prep_cif} may modify the size and
> +alignment of some types, depending on the chosen ABI. On these
> +platforms, if you switch between ABIs, you must ensure that there is
> +only one call to @code{ffi_prep_cif} at a time.
> +
> +Currently the only affected platform is PowerPC and the only affected
> +type is @code{long double}.
> +@end itemize
>
> @node Missing Features
> @chapter Missing Features
> @@ -749,8 +909,6 @@ There is no support for bit fields in structures.
>
> @item
> The ``raw'' API is undocumented.
> -@c argument promotion?
> -@c unions?
> @c anything else?
> @end itemize
>