Commit 3521ba8b by Alan Modra

PowerPC64 ELFv2 support

PowerPC64 ELFv2 support
	* src/powerpc/ffitarget.h: Import from upstream.
	* src/powerpc/ffi.c: Likewise.
	* src/powerpc/linux64.S: Likewise.
	* src/powerpc/linux64_closure.S: Likewise.
	* doc/libffi.texi: Likewise.
	* testsuite/libffi.call/cls_double_va.c: Likewise.
	* testsuite/libffi.call/cls_longdouble_va.c: Likewise.

From-SVN: r204917
parent abe6cd5d
...@@ -184,11 +184,11 @@ This calls the function @var{fn} according to the description given in ...@@ -184,11 +184,11 @@ This calls the function @var{fn} according to the description given in
@var{rvalue} is a pointer to a chunk of memory that will hold the @var{rvalue} is a pointer to a chunk of memory that will hold the
result of the function call. This must be large enough to hold the result of the function call. This must be large enough to hold the
result and must be suitably aligned; it is the caller's responsibility result, no smaller than the system register size (generally 32 or 64
bits), and must be suitably aligned; it is the caller's responsibility
to ensure this. If @var{cif} declares that the function returns to ensure this. If @var{cif} declares that the function returns
@code{void} (using @code{ffi_type_void}), then @var{rvalue} is @code{void} (using @code{ffi_type_void}), then @var{rvalue} is
ignored. If @var{rvalue} is @samp{NULL}, then the return value is ignored.
discarded.
@var{avalues} is a vector of @code{void *} pointers that point to the @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} memory locations holding the argument values for a call. If @var{cif}
...@@ -214,7 +214,7 @@ int main() ...@@ -214,7 +214,7 @@ int main()
ffi_type *args[1]; ffi_type *args[1];
void *values[1]; void *values[1];
char *s; char *s;
int rc; ffi_arg rc;
/* Initialize the argument info vectors */ /* Initialize the argument info vectors */
args[0] = &ffi_type_pointer; args[0] = &ffi_type_pointer;
...@@ -222,7 +222,7 @@ int main() ...@@ -222,7 +222,7 @@ int main()
/* Initialize the cif */ /* Initialize the cif */
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
&ffi_type_uint, args) == FFI_OK) &ffi_type_sint, args) == FFI_OK)
@{ @{
s = "Hello World!"; s = "Hello World!";
ffi_call(&cif, puts, &rc, values); ffi_call(&cif, puts, &rc, values);
...@@ -360,7 +360,7 @@ You must first describe the structure to @samp{libffi} by creating a ...@@ -360,7 +360,7 @@ You must first describe the structure to @samp{libffi} by creating a
new @code{ffi_type} object for it. new @code{ffi_type} object for it.
@tindex ffi_type @tindex ffi_type
@deftp ffi_type @deftp {Data type} ffi_type
The @code{ffi_type} has the following members: The @code{ffi_type} has the following members:
@table @code @table @code
@item size_t size @item size_t size
...@@ -414,6 +414,7 @@ Here is the corresponding code to describe this struct to ...@@ -414,6 +414,7 @@ Here is the corresponding code to describe this struct to
int i; int i;
tm_type.size = tm_type.alignment = 0; tm_type.size = tm_type.alignment = 0;
tm_type.type = FFI_TYPE_STRUCT;
tm_type.elements = &tm_type_elements; tm_type.elements = &tm_type_elements;
for (i = 0; i < 9; i++) for (i = 0; i < 9; i++)
...@@ -540,21 +541,23 @@ A trivial example that creates a new @code{puts} by binding ...@@ -540,21 +541,23 @@ A trivial example that creates a new @code{puts} by binding
#include <ffi.h> #include <ffi.h>
/* Acts like puts with the file given at time of enclosure. */ /* Acts like puts with the file given at time of enclosure. */
void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[], void puts_binding(ffi_cif *cif, void *ret, void* args[],
FILE *stream) void *stream)
@{ @{
*ret = fputs(*(char **)args[0], stream); *(ffi_arg *)ret = fputs(*(char **)args[0], (FILE *)stream);
@} @}
typedef int (*puts_t)(char *);
int main() int main()
@{ @{
ffi_cif cif; ffi_cif cif;
ffi_type *args[1]; ffi_type *args[1];
ffi_closure *closure; ffi_closure *closure;
int (*bound_puts)(char *); void *bound_puts;
int rc; int rc;
/* Allocate closure and bound_puts */ /* Allocate closure and bound_puts */
closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts); closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);
...@@ -565,13 +568,13 @@ int main() ...@@ -565,13 +568,13 @@ int main()
/* Initialize the cif */ /* Initialize the cif */
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
&ffi_type_uint, args) == FFI_OK) &ffi_type_sint, args) == FFI_OK)
@{ @{
/* Initialize the closure, setting stream to stdout */ /* Initialize the closure, setting stream to stdout */
if (ffi_prep_closure_loc(closure, &cif, puts_binding, if (ffi_prep_closure_loc(closure, &cif, puts_binding,
stdout, bound_puts) == FFI_OK) stdout, bound_puts) == FFI_OK)
@{ @{
rc = bound_puts("Hello World!"); rc = ((puts_t)bound_puts)("Hello World!");
/* rc now holds the result of the call to fputs */ /* rc now holds the result of the call to fputs */
@} @}
@} @}
......
...@@ -106,6 +106,10 @@ typedef enum ffi_abi { ...@@ -106,6 +106,10 @@ typedef enum ffi_abi {
#define FFI_CLOSURES 1 #define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0 #define FFI_NATIVE_RAW_API 0
#if defined (POWERPC) || defined (POWERPC_FREEBSD)
# define FFI_TARGET_SPECIFIC_VARIADIC 1
# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
#endif
/* For additional types like the below, take care about the order in /* For additional types like the below, take care about the order in
ppc_closures.S. They must follow after the FFI_TYPE_LAST. */ ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
...@@ -118,14 +122,23 @@ typedef enum ffi_abi { ...@@ -118,14 +122,23 @@ typedef enum ffi_abi {
defined in ffi.c, to determine the exact return type and its size. */ defined in ffi.c, to determine the exact return type and its size. */
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2) #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
#if defined(POWERPC64) || defined(POWERPC_AIX) /* Used by ELFv2 for homogenous structure returns. */
#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_TYPE_LAST + 1)
#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_TYPE_LAST + 2)
#define FFI_V2_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 3)
#if _CALL_ELF == 2
# define FFI_TRAMPOLINE_SIZE 32
#else
# if defined(POWERPC64) || defined(POWERPC_AIX)
# if defined(POWERPC_DARWIN64) # if defined(POWERPC_DARWIN64)
# define FFI_TRAMPOLINE_SIZE 48 # define FFI_TRAMPOLINE_SIZE 48
# else # else
# define FFI_TRAMPOLINE_SIZE 24 # define FFI_TRAMPOLINE_SIZE 24
# endif # endif
#else /* POWERPC || POWERPC_AIX */ # else /* POWERPC || POWERPC_AIX */
# define FFI_TRAMPOLINE_SIZE 40 # define FFI_TRAMPOLINE_SIZE 40
# endif
#endif #endif
#ifndef LIBFFI_ASM #ifndef LIBFFI_ASM
......
...@@ -32,15 +32,22 @@ ...@@ -32,15 +32,22 @@
#ifdef __powerpc64__ #ifdef __powerpc64__
.hidden ffi_call_LINUX64 .hidden ffi_call_LINUX64
.globl ffi_call_LINUX64 .globl ffi_call_LINUX64
# if _CALL_ELF == 2
.text
ffi_call_LINUX64:
addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha
addi %r2, %r2, .TOC.-ffi_call_LINUX64@l
.localentry ffi_call_LINUX64, . - ffi_call_LINUX64
# else
.section ".opd","aw" .section ".opd","aw"
.align 3 .align 3
ffi_call_LINUX64: ffi_call_LINUX64:
#ifdef _CALL_LINUX # ifdef _CALL_LINUX
.quad .L.ffi_call_LINUX64,.TOC.@tocbase,0 .quad .L.ffi_call_LINUX64,.TOC.@tocbase,0
.type ffi_call_LINUX64,@function .type ffi_call_LINUX64,@function
.text .text
.L.ffi_call_LINUX64: .L.ffi_call_LINUX64:
#else # else
.hidden .ffi_call_LINUX64 .hidden .ffi_call_LINUX64
.globl .ffi_call_LINUX64 .globl .ffi_call_LINUX64
.quad .ffi_call_LINUX64,.TOC.@tocbase,0 .quad .ffi_call_LINUX64,.TOC.@tocbase,0
...@@ -48,7 +55,8 @@ ffi_call_LINUX64: ...@@ -48,7 +55,8 @@ ffi_call_LINUX64:
.type .ffi_call_LINUX64,@function .type .ffi_call_LINUX64,@function
.text .text
.ffi_call_LINUX64: .ffi_call_LINUX64:
#endif # endif
# endif
.LFB1: .LFB1:
mflr %r0 mflr %r0
std %r28, -32(%r1) std %r28, -32(%r1)
...@@ -63,26 +71,35 @@ ffi_call_LINUX64: ...@@ -63,26 +71,35 @@ ffi_call_LINUX64:
mr %r31, %r5 /* flags, */ mr %r31, %r5 /* flags, */
mr %r30, %r6 /* rvalue, */ mr %r30, %r6 /* rvalue, */
mr %r29, %r7 /* function address. */ mr %r29, %r7 /* function address. */
/* Save toc pointer, not for the ffi_prep_args64 call, but for the later
bctrl function call. */
# if _CALL_ELF == 2
std %r2, 24(%r1)
# else
std %r2, 40(%r1) std %r2, 40(%r1)
# endif
/* Call ffi_prep_args64. */ /* Call ffi_prep_args64. */
mr %r4, %r1 mr %r4, %r1
#ifdef _CALL_LINUX # if defined _CALL_LINUX || _CALL_ELF == 2
bl ffi_prep_args64 bl ffi_prep_args64
#else # else
bl .ffi_prep_args64 bl .ffi_prep_args64
#endif # endif
ld %r0, 0(%r29) # if _CALL_ELF == 2
mr %r12, %r29
# else
ld %r12, 0(%r29)
ld %r2, 8(%r29) ld %r2, 8(%r29)
ld %r11, 16(%r29) ld %r11, 16(%r29)
# endif
/* Now do the call. */ /* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */ /* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40, %r31 mtcrf 0x40, %r31
/* Get the address to call into CTR. */ /* Get the address to call into CTR. */
mtctr %r0 mtctr %r12
/* Load all those argument registers. */ /* Load all those argument registers. */
ld %r3, -32-(8*8)(%r28) ld %r3, -32-(8*8)(%r28)
ld %r4, -32-(7*8)(%r28) ld %r4, -32-(7*8)(%r28)
...@@ -117,12 +134,17 @@ ffi_call_LINUX64: ...@@ -117,12 +134,17 @@ ffi_call_LINUX64:
/* This must follow the call immediately, the unwinder /* This must follow the call immediately, the unwinder
uses this to find out if r2 has been saved or not. */ uses this to find out if r2 has been saved or not. */
# if _CALL_ELF == 2
ld %r2, 24(%r1)
# else
ld %r2, 40(%r1) ld %r2, 40(%r1)
# endif
/* Now, deal with the return value. */ /* Now, deal with the return value. */
mtcrf 0x01, %r31 mtcrf 0x01, %r31
bt- 30, .Ldone_return_value bt 31, .Lstruct_return_value
bt- 29, .Lfp_return_value bt 30, .Ldone_return_value
bt 29, .Lfp_return_value
std %r3, 0(%r30) std %r3, 0(%r30)
/* Fall through... */ /* Fall through... */
...@@ -130,7 +152,7 @@ ffi_call_LINUX64: ...@@ -130,7 +152,7 @@ ffi_call_LINUX64:
/* Restore the registers we used and return. */ /* Restore the registers we used and return. */
mr %r1, %r28 mr %r1, %r28
ld %r0, 16(%r28) ld %r0, 16(%r28)
ld %r28, -32(%r1) ld %r28, -32(%r28)
mtlr %r0 mtlr %r0
ld %r29, -24(%r1) ld %r29, -24(%r1)
ld %r30, -16(%r1) ld %r30, -16(%r1)
...@@ -147,14 +169,48 @@ ffi_call_LINUX64: ...@@ -147,14 +169,48 @@ ffi_call_LINUX64:
.Lfloat_return_value: .Lfloat_return_value:
stfs %f1, 0(%r30) stfs %f1, 0(%r30)
b .Ldone_return_value b .Ldone_return_value
.Lstruct_return_value:
bf 29, .Lsmall_struct
bf 28, .Lfloat_homog_return_value
stfd %f1, 0(%r30)
stfd %f2, 8(%r30)
stfd %f3, 16(%r30)
stfd %f4, 24(%r30)
stfd %f5, 32(%r30)
stfd %f6, 40(%r30)
stfd %f7, 48(%r30)
stfd %f8, 56(%r30)
b .Ldone_return_value
.Lfloat_homog_return_value:
stfs %f1, 0(%r30)
stfs %f2, 4(%r30)
stfs %f3, 8(%r30)
stfs %f4, 12(%r30)
stfs %f5, 16(%r30)
stfs %f6, 20(%r30)
stfs %f7, 24(%r30)
stfs %f8, 28(%r30)
b .Ldone_return_value
.Lsmall_struct:
std %r3, 0(%r30)
std %r4, 8(%r30)
b .Ldone_return_value
.LFE1: .LFE1:
.long 0 .long 0
.byte 0,12,0,1,128,4,0,0 .byte 0,12,0,1,128,4,0,0
#ifdef _CALL_LINUX # if _CALL_ELF == 2
.size ffi_call_LINUX64,.-ffi_call_LINUX64
# else
# ifdef _CALL_LINUX
.size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64
#else # else
.size .ffi_call_LINUX64,.-.ffi_call_LINUX64 .size .ffi_call_LINUX64,.-.ffi_call_LINUX64
#endif # endif
# endif
.section .eh_frame,EH_FRAME_FLAGS,@progbits .section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1: .Lframe1:
...@@ -197,8 +253,8 @@ ffi_call_LINUX64: ...@@ -197,8 +253,8 @@ ffi_call_LINUX64:
.uleb128 0x4 .uleb128 0x4
.align 3 .align 3
.LEFDE1: .LEFDE1:
#endif
#if defined __ELF__ && defined __linux__ # if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
.section .note.GNU-stack,"",@progbits .section .note.GNU-stack,"",@progbits
# endif
#endif #endif
...@@ -33,15 +33,22 @@ ...@@ -33,15 +33,22 @@
#ifdef __powerpc64__ #ifdef __powerpc64__
FFI_HIDDEN (ffi_closure_LINUX64) FFI_HIDDEN (ffi_closure_LINUX64)
.globl ffi_closure_LINUX64 .globl ffi_closure_LINUX64
# if _CALL_ELF == 2
.text
ffi_closure_LINUX64:
addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l
.localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
# else
.section ".opd","aw" .section ".opd","aw"
.align 3 .align 3
ffi_closure_LINUX64: ffi_closure_LINUX64:
#ifdef _CALL_LINUX # ifdef _CALL_LINUX
.quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0
.type ffi_closure_LINUX64,@function .type ffi_closure_LINUX64,@function
.text .text
.L.ffi_closure_LINUX64: .L.ffi_closure_LINUX64:
#else # else
FFI_HIDDEN (.ffi_closure_LINUX64) FFI_HIDDEN (.ffi_closure_LINUX64)
.globl .ffi_closure_LINUX64 .globl .ffi_closure_LINUX64
.quad .ffi_closure_LINUX64,.TOC.@tocbase,0 .quad .ffi_closure_LINUX64,.TOC.@tocbase,0
...@@ -49,61 +56,103 @@ ffi_closure_LINUX64: ...@@ -49,61 +56,103 @@ ffi_closure_LINUX64:
.type .ffi_closure_LINUX64,@function .type .ffi_closure_LINUX64,@function
.text .text
.ffi_closure_LINUX64: .ffi_closure_LINUX64:
#endif # endif
# endif
# if _CALL_ELF == 2
# 32 byte special reg save area + 64 byte parm save area and retval
# + 13*8 fpr save area + round to 16
# define STACKFRAME 208
# define PARMSAVE 32
# No parameter save area is needed for the call to ffi_closure_helper_LINUX64,
# so return value can start there.
# define RETVAL PARMSAVE
# else
# 48 bytes special reg save area + 64 bytes parm save area
# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
# define STACKFRAME 240
# define PARMSAVE 48
# define RETVAL PARMSAVE+64
# endif
.LFB1: .LFB1:
# save general regs into parm save area # if _CALL_ELF == 2
std %r3, 48(%r1) ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif
std %r4, 56(%r1)
std %r5, 64(%r1)
std %r6, 72(%r1)
mflr %r0 mflr %r0
lwz %r12, 28(%r12) # cif->flags
mtcrf 0x40, %r12
addi %r12, %r1, PARMSAVE
bt 7, .Lparmsave
# Our caller has not allocated a parameter save area.
# We need to allocate one here and use it to pass gprs to
# ffi_closure_helper_LINUX64. The return value area will do.
addi %r12, %r1, -STACKFRAME+RETVAL
.Lparmsave:
std %r0, 16(%r1)
# Save general regs into parm save area
std %r3, 0(%r12)
std %r4, 8(%r12)
std %r5, 16(%r12)
std %r6, 24(%r12)
std %r7, 32(%r12)
std %r8, 40(%r12)
std %r9, 48(%r12)
std %r10, 56(%r12)
# load up the pointer to the parm save area
mr %r5, %r12
# else
mflr %r0
# Save general regs into parm save area
# This is the parameter save area set up by our caller.
std %r3, PARMSAVE+0(%r1)
std %r4, PARMSAVE+8(%r1)
std %r5, PARMSAVE+16(%r1)
std %r6, PARMSAVE+24(%r1)
std %r7, PARMSAVE+32(%r1)
std %r8, PARMSAVE+40(%r1)
std %r9, PARMSAVE+48(%r1)
std %r10, PARMSAVE+56(%r1)
std %r7, 80(%r1)
std %r8, 88(%r1)
std %r9, 96(%r1)
std %r10, 104(%r1)
std %r0, 16(%r1) std %r0, 16(%r1)
# mandatory 48 bytes special reg save area + 64 bytes parm save area # load up the pointer to the parm save area
# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 addi %r5, %r1, PARMSAVE
stdu %r1, -240(%r1) # endif
.LCFI0:
# next save fpr 1 to fpr 13 # next save fpr 1 to fpr 13
stfd %f1, 128+(0*8)(%r1) stfd %f1, -104+(0*8)(%r1)
stfd %f2, 128+(1*8)(%r1) stfd %f2, -104+(1*8)(%r1)
stfd %f3, 128+(2*8)(%r1) stfd %f3, -104+(2*8)(%r1)
stfd %f4, 128+(3*8)(%r1) stfd %f4, -104+(3*8)(%r1)
stfd %f5, 128+(4*8)(%r1) stfd %f5, -104+(4*8)(%r1)
stfd %f6, 128+(5*8)(%r1) stfd %f6, -104+(5*8)(%r1)
stfd %f7, 128+(6*8)(%r1) stfd %f7, -104+(6*8)(%r1)
stfd %f8, 128+(7*8)(%r1) stfd %f8, -104+(7*8)(%r1)
stfd %f9, 128+(8*8)(%r1) stfd %f9, -104+(8*8)(%r1)
stfd %f10, 128+(9*8)(%r1) stfd %f10, -104+(9*8)(%r1)
stfd %f11, 128+(10*8)(%r1) stfd %f11, -104+(10*8)(%r1)
stfd %f12, 128+(11*8)(%r1) stfd %f12, -104+(11*8)(%r1)
stfd %f13, 128+(12*8)(%r1) stfd %f13, -104+(12*8)(%r1)
# set up registers for the routine that actually does the work # load up the pointer to the saved fpr registers */
# get the context pointer from the trampoline addi %r6, %r1, -104
mr %r3, %r11
# now load up the pointer to the result storage # load up the pointer to the result storage
addi %r4, %r1, 112 addi %r4, %r1, -STACKFRAME+RETVAL
# now load up the pointer to the parameter save area stdu %r1, -STACKFRAME(%r1)
# in the previous frame .LCFI0:
addi %r5, %r1, 240 + 48
# now load up the pointer to the saved fpr registers */ # get the context pointer from the trampoline
addi %r6, %r1, 128 mr %r3, %r11
# make the call # make the call
#ifdef _CALL_LINUX # if defined _CALL_LINUX || _CALL_ELF == 2
bl ffi_closure_helper_LINUX64 bl ffi_closure_helper_LINUX64
#else # else
bl .ffi_closure_helper_LINUX64 bl .ffi_closure_helper_LINUX64
#endif # endif
.Lret: .Lret:
# now r3 contains the return type # now r3 contains the return type
...@@ -112,10 +161,12 @@ ffi_closure_LINUX64: ...@@ -112,10 +161,12 @@ ffi_closure_LINUX64:
# look up the proper starting point in table # look up the proper starting point in table
# by using return type as offset # by using return type as offset
ld %r0, STACKFRAME+16(%r1)
cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
bge .Lsmall
mflr %r4 # move address of .Lret to r4 mflr %r4 # move address of .Lret to r4
sldi %r3, %r3, 4 # now multiply return type by 16 sldi %r3, %r3, 4 # now multiply return type by 16
addi %r4, %r4, .Lret_type0 - .Lret addi %r4, %r4, .Lret_type0 - .Lret
ld %r0, 240+16(%r1)
add %r3, %r3, %r4 # add contents of table to table address add %r3, %r3, %r4 # add contents of table to table address
mtctr %r3 mtctr %r3
bctr # jump to it bctr # jump to it
...@@ -128,117 +179,175 @@ ffi_closure_LINUX64: ...@@ -128,117 +179,175 @@ ffi_closure_LINUX64:
.Lret_type0: .Lret_type0:
# case FFI_TYPE_VOID # case FFI_TYPE_VOID
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
nop nop
# case FFI_TYPE_INT # case FFI_TYPE_INT
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lwa %r3, 112+0(%r1) lwa %r3, RETVAL+0(%r1)
#else # else
lwa %r3, 112+4(%r1) lwa %r3, RETVAL+4(%r1)
#endif # endif
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_FLOAT # case FFI_TYPE_FLOAT
lfs %f1, 112+0(%r1) lfs %f1, RETVAL+0(%r1)
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_DOUBLE # case FFI_TYPE_DOUBLE
lfd %f1, 112+0(%r1) lfd %f1, RETVAL+0(%r1)
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_LONGDOUBLE # case FFI_TYPE_LONGDOUBLE
lfd %f1, 112+0(%r1) lfd %f1, RETVAL+0(%r1)
mtlr %r0 mtlr %r0
lfd %f2, 112+8(%r1) lfd %f2, RETVAL+8(%r1)
b .Lfinish b .Lfinish
# case FFI_TYPE_UINT8 # case FFI_TYPE_UINT8
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lbz %r3, 112+0(%r1) lbz %r3, RETVAL+0(%r1)
#else # else
lbz %r3, 112+7(%r1) lbz %r3, RETVAL+7(%r1)
#endif # endif
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_SINT8 # case FFI_TYPE_SINT8
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lbz %r3, 112+0(%r1) lbz %r3, RETVAL+0(%r1)
#else # else
lbz %r3, 112+7(%r1) lbz %r3, RETVAL+7(%r1)
#endif # endif
extsb %r3,%r3 extsb %r3,%r3
mtlr %r0 mtlr %r0
b .Lfinish b .Lfinish
# case FFI_TYPE_UINT16 # case FFI_TYPE_UINT16
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lhz %r3, 112+0(%r1) lhz %r3, RETVAL+0(%r1)
#else # else
lhz %r3, 112+6(%r1) lhz %r3, RETVAL+6(%r1)
#endif # endif
mtlr %r0 mtlr %r0
.Lfinish: .Lfinish:
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_SINT16 # case FFI_TYPE_SINT16
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lha %r3, 112+0(%r1) lha %r3, RETVAL+0(%r1)
#else # else
lha %r3, 112+6(%r1) lha %r3, RETVAL+6(%r1)
#endif # endif
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_UINT32 # case FFI_TYPE_UINT32
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lwz %r3, 112+0(%r1) lwz %r3, RETVAL+0(%r1)
#else # else
lwz %r3, 112+4(%r1) lwz %r3, RETVAL+4(%r1)
#endif # endif
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_SINT32 # case FFI_TYPE_SINT32
#ifdef __LITTLE_ENDIAN__ # ifdef __LITTLE_ENDIAN__
lwa %r3, 112+0(%r1) lwa %r3, RETVAL+0(%r1)
#else # else
lwa %r3, 112+4(%r1) lwa %r3, RETVAL+4(%r1)
#endif # endif
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_UINT64 # case FFI_TYPE_UINT64
ld %r3, 112+0(%r1) ld %r3, RETVAL+0(%r1)
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_SINT64 # case FFI_TYPE_SINT64
ld %r3, 112+0(%r1) ld %r3, RETVAL+0(%r1)
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
# case FFI_TYPE_STRUCT # case FFI_TYPE_STRUCT
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 addi %r1, %r1, STACKFRAME
blr blr
nop nop
# case FFI_TYPE_POINTER # case FFI_TYPE_POINTER
ld %r3, 112+0(%r1) ld %r3, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
blr
# case FFI_V2_TYPE_FLOAT_HOMOG
lfs %f1, RETVAL+0(%r1)
lfs %f2, RETVAL+4(%r1)
lfs %f3, RETVAL+8(%r1)
b .Lmorefloat
# case FFI_V2_TYPE_DOUBLE_HOMOG
lfd %f1, RETVAL+0(%r1)
lfd %f2, RETVAL+8(%r1)
lfd %f3, RETVAL+16(%r1)
lfd %f4, RETVAL+24(%r1)
mtlr %r0
lfd %f5, RETVAL+32(%r1)
lfd %f6, RETVAL+40(%r1)
lfd %f7, RETVAL+48(%r1)
lfd %f8, RETVAL+56(%r1)
addi %r1, %r1, STACKFRAME
blr
.Lmorefloat:
lfs %f4, RETVAL+12(%r1)
mtlr %r0
lfs %f5, RETVAL+16(%r1)
lfs %f6, RETVAL+20(%r1)
lfs %f7, RETVAL+24(%r1)
lfs %f8, RETVAL+28(%r1)
addi %r1, %r1, STACKFRAME
blr
.Lsmall:
# ifdef __LITTLE_ENDIAN__
ld %r3,RETVAL+0(%r1)
mtlr %r0
ld %r4,RETVAL+8(%r1)
addi %r1, %r1, STACKFRAME
blr
# else
# A struct smaller than a dword is returned in the low bits of r3
# ie. right justified. Larger structs are passed left justified
# in r3 and r4. The return value area on the stack will have
# the structs as they are usually stored in memory.
cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
neg %r5, %r3
ld %r3,RETVAL+0(%r1)
blt .Lsmalldown
mtlr %r0
ld %r4,RETVAL+8(%r1)
addi %r1, %r1, STACKFRAME
blr
.Lsmalldown:
addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
mtlr %r0 mtlr %r0
addi %r1, %r1, 240 sldi %r5, %r5, 3
addi %r1, %r1, STACKFRAME
srd %r3, %r3, %r5
blr blr
# esac # endif
.LFE1: .LFE1:
.long 0 .long 0
.byte 0,12,0,1,128,0,0,0 .byte 0,12,0,1,128,0,0,0
#ifdef _CALL_LINUX # if _CALL_ELF == 2
.size ffi_closure_LINUX64,.-ffi_closure_LINUX64
# else
# ifdef _CALL_LINUX
.size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
#else # else
.size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
#endif # endif
# endif
.section .eh_frame,EH_FRAME_FLAGS,@progbits .section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1: .Lframe1:
...@@ -267,14 +376,14 @@ ffi_closure_LINUX64: ...@@ -267,14 +376,14 @@ ffi_closure_LINUX64:
.byte 0x2 # DW_CFA_advance_loc1 .byte 0x2 # DW_CFA_advance_loc1
.byte .LCFI0-.LFB1 .byte .LCFI0-.LFB1
.byte 0xe # DW_CFA_def_cfa_offset .byte 0xe # DW_CFA_def_cfa_offset
.uleb128 240 .uleb128 STACKFRAME
.byte 0x11 # DW_CFA_offset_extended_sf .byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41 .uleb128 0x41
.sleb128 -2 .sleb128 -2
.align 3 .align 3
.LEFDE1: .LEFDE1:
#endif
#if defined __ELF__ && defined __linux__ # if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits .section .note.GNU-stack,"",@progbits
# endif
#endif #endif
...@@ -38,26 +38,24 @@ int main (void) ...@@ -38,26 +38,24 @@ int main (void)
/* This printf call is variadic */ /* This printf call is variadic */
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK); arg_types) == FFI_OK);
args[0] = &format; args[0] = &format;
args[1] = &doubleArg; args[1] = &doubleArg;
args[2] = NULL; args[2] = NULL;
ffi_call(&cif, FFI_FN(printf), &res, args); ffi_call(&cif, FFI_FN(printf), &res, args);
// { dg-output "7.0" } /* { dg-output "7.0" } */
printf("res: %d\n", (int) res); printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" } /* { dg-output "\nres: 4" } */
/* The call to cls_double_va_fn is static, so have to use a normal prep_cif */ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL,
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK); code) == FFI_OK);
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK); res = ((int(*)(char*, ...))(code))(format, doubleArg);
/* { dg-output "\n7.0" } */
res = ((int(*)(char*, double))(code))(format, doubleArg);
// { dg-output "\n7.0" }
printf("res: %d\n", (int) res); printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" } /* { dg-output "\nres: 4" } */
exit(0); exit(0);
} }
...@@ -38,27 +38,24 @@ int main (void) ...@@ -38,27 +38,24 @@ int main (void)
/* This printf call is variadic */ /* This printf call is variadic */
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK); arg_types) == FFI_OK);
args[0] = &format; args[0] = &format;
args[1] = &ldArg; args[1] = &ldArg;
args[2] = NULL; args[2] = NULL;
ffi_call(&cif, FFI_FN(printf), &res, args); ffi_call(&cif, FFI_FN(printf), &res, args);
// { dg-output "7.0" } /* { dg-output "7.0" } */
printf("res: %d\n", (int) res); printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" } /* { dg-output "\nres: 4" } */
/* The call to cls_longdouble_va_fn is static, so have to use a normal prep_cif */ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL,
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, code) == FFI_OK);
arg_types) == FFI_OK);
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK); res = ((int(*)(char*, ...))(code))(format, ldArg);
/* { dg-output "\n7.0" } */
res = ((int(*)(char*, long double))(code))(format, ldArg);
// { dg-output "\n7.0" }
printf("res: %d\n", (int) res); printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" } /* { dg-output "\nres: 4" } */
exit(0); exit(0);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment