add ffi_get_struct_offsets
This commit is contained in:
@@ -440,7 +440,8 @@ on the chosen ABI.
|
|||||||
|
|
||||||
@item
|
@item
|
||||||
The size and alignment of a new structure type will not be set by
|
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}.
|
@code{libffi} until it has been passed to @code{ffi_prep_cif} or
|
||||||
|
@code{ffi_get_struct_offsets}.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
A structure type cannot be shared across ABIs. Instead each ABI needs
|
A structure type cannot be shared across ABIs. Instead each ABI needs
|
||||||
@@ -448,8 +449,9 @@ its own copy of the structure type.
|
|||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
So, before examining these fields, it is safest to pass the
|
So, before examining these fields, it is safest to pass the
|
||||||
@code{ffi_type} object to @code{ffi_prep_cif} first. This function
|
@code{ffi_type} object to @code{ffi_prep_cif} or
|
||||||
will do all the needed setup.
|
@code{ffi_get_struct_offsets} first. This function will do all the
|
||||||
|
needed setup.
|
||||||
|
|
||||||
@example
|
@example
|
||||||
ffi_type *desired_type;
|
ffi_type *desired_type;
|
||||||
@@ -463,6 +465,28 @@ if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK)
|
|||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@code{libffi} also provides a way to get the offsets of the members of
|
||||||
|
a structure.
|
||||||
|
|
||||||
|
@findex ffi_get_struct_offsets
|
||||||
|
@defun ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
|
||||||
|
Compute the offset of each element of the given structure type.
|
||||||
|
@var{abi} is the ABI to use; this is needed because in some cases the
|
||||||
|
layout depends on the ABI.
|
||||||
|
|
||||||
|
@var{sizes} is an out parameter. The caller is responsible for
|
||||||
|
providing enough space for all the results to be written -- one
|
||||||
|
element per element type in @var{struct_type}. If @var{sizes} is
|
||||||
|
@code{NULL}, then the type will be laid out but not otherwise
|
||||||
|
modified. This can be useful for accessing the type's size or layout,
|
||||||
|
as mentioned above.
|
||||||
|
|
||||||
|
This function returns @code{FFI_OK} on success; @code{FFI_BAD_ABI} if
|
||||||
|
@var{abi} is invalid; or @code{FFI_BAD_TYPEDEF} if @var{struct_type}
|
||||||
|
is invalid in some way. Note that only @code{FFI_STRUCT} types are
|
||||||
|
valid here.
|
||||||
|
@end defun
|
||||||
|
|
||||||
@node Arrays Unions Enums
|
@node Arrays Unions Enums
|
||||||
@subsection Arrays, Unions, and Enumerations
|
@subsection Arrays, Unions, and Enumerations
|
||||||
|
|
||||||
|
|||||||
@@ -458,6 +458,9 @@ void ffi_call(ffi_cif *cif,
|
|||||||
void *rvalue,
|
void *rvalue,
|
||||||
void **avalue);
|
void **avalue);
|
||||||
|
|
||||||
|
ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
|
||||||
|
size_t *offsets);
|
||||||
|
|
||||||
/* Useful for eliminating compiler warnings */
|
/* Useful for eliminating compiler warnings */
|
||||||
#define FFI_FN(f) ((void (*)(void))f)
|
#define FFI_FN(f) ((void (*)(void))f)
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
/* Perform machine independent initialization of aggregate type
|
/* Perform machine independent initialization of aggregate type
|
||||||
specifications. */
|
specifications. */
|
||||||
|
|
||||||
static ffi_status initialize_aggregate(ffi_type *arg)
|
static ffi_status initialize_aggregate(ffi_type *arg, size_t *offsets)
|
||||||
{
|
{
|
||||||
ffi_type **ptr;
|
ffi_type **ptr;
|
||||||
|
|
||||||
@@ -52,13 +52,15 @@ static ffi_status initialize_aggregate(ffi_type *arg)
|
|||||||
while ((*ptr) != NULL)
|
while ((*ptr) != NULL)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(((*ptr)->size == 0)
|
if (UNLIKELY(((*ptr)->size == 0)
|
||||||
&& (initialize_aggregate((*ptr)) != FFI_OK)))
|
&& (initialize_aggregate((*ptr), NULL) != FFI_OK)))
|
||||||
return FFI_BAD_TYPEDEF;
|
return FFI_BAD_TYPEDEF;
|
||||||
|
|
||||||
/* Perform a sanity check on the argument type */
|
/* Perform a sanity check on the argument type */
|
||||||
FFI_ASSERT_VALID_TYPE(*ptr);
|
FFI_ASSERT_VALID_TYPE(*ptr);
|
||||||
|
|
||||||
arg->size = ALIGN(arg->size, (*ptr)->alignment);
|
arg->size = ALIGN(arg->size, (*ptr)->alignment);
|
||||||
|
if (offsets)
|
||||||
|
*offsets++ = arg->size;
|
||||||
arg->size += (*ptr)->size;
|
arg->size += (*ptr)->size;
|
||||||
|
|
||||||
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
|
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
|
||||||
@@ -133,7 +135,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize the return type if necessary */
|
/* Initialize the return type if necessary */
|
||||||
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
|
if ((cif->rtype->size == 0)
|
||||||
|
&& (initialize_aggregate(cif->rtype, NULL) != FFI_OK))
|
||||||
return FFI_BAD_TYPEDEF;
|
return FFI_BAD_TYPEDEF;
|
||||||
|
|
||||||
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
@@ -164,7 +167,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|||||||
{
|
{
|
||||||
|
|
||||||
/* Initialize any uninitialized aggregate type definitions */
|
/* Initialize any uninitialized aggregate type definitions */
|
||||||
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
|
if (((*ptr)->size == 0)
|
||||||
|
&& (initialize_aggregate((*ptr), NULL) != FFI_OK))
|
||||||
return FFI_BAD_TYPEDEF;
|
return FFI_BAD_TYPEDEF;
|
||||||
|
|
||||||
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
@@ -240,3 +244,18 @@ ffi_prep_closure (ffi_closure* closure,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ffi_status
|
||||||
|
ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
|
||||||
|
{
|
||||||
|
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
|
||||||
|
return FFI_BAD_ABI;
|
||||||
|
if (struct_type->type != FFI_TYPE_STRUCT)
|
||||||
|
return FFI_BAD_TYPEDEF;
|
||||||
|
|
||||||
|
#if HAVE_LONG_DOUBLE_VARIANT
|
||||||
|
ffi_prep_types (abi);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return initialize_aggregate(struct_type, offsets);
|
||||||
|
}
|
||||||
|
|||||||
46
testsuite/libffi.call/offsets.c
Normal file
46
testsuite/libffi.call/offsets.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/* Area: Struct layout
|
||||||
|
Purpose: Test ffi_get_struct_offsets
|
||||||
|
Limitations: none.
|
||||||
|
PR: none.
|
||||||
|
Originator: Tom Tromey. */
|
||||||
|
|
||||||
|
/* { dg-do run } */
|
||||||
|
#include "ffitest.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct test_1
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
float f;
|
||||||
|
char c2;
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
ffi_type test_1_type;
|
||||||
|
ffi_type *test_1_elements[5];
|
||||||
|
size_t test_1_offsets[4];
|
||||||
|
|
||||||
|
test_1_elements[0] = &ffi_type_schar;
|
||||||
|
test_1_elements[1] = &ffi_type_float;
|
||||||
|
test_1_elements[2] = &ffi_type_schar;
|
||||||
|
test_1_elements[3] = &ffi_type_sint;
|
||||||
|
test_1_elements[4] = NULL;
|
||||||
|
|
||||||
|
test_1_type.size = 0;
|
||||||
|
test_1_type.alignment = 0;
|
||||||
|
test_1_type.type = FFI_TYPE_STRUCT;
|
||||||
|
test_1_type.elements = test_1_elements;
|
||||||
|
|
||||||
|
CHECK (ffi_get_struct_offsets (FFI_DEFAULT_ABI, &test_1_type, test_1_offsets)
|
||||||
|
== FFI_OK);
|
||||||
|
CHECK (test_1_type.size == sizeof (struct test_1));
|
||||||
|
CHECK (offsetof (struct test_1, c) == test_1_offsets[0]);
|
||||||
|
CHECK (offsetof (struct test_1, f) == test_1_offsets[1]);
|
||||||
|
CHECK (offsetof (struct test_1, c2) == test_1_offsets[2]);
|
||||||
|
CHECK (offsetof (struct test_1, i) == test_1_offsets[3]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user