diff options
Diffstat (limited to 'libffi/src')
-rw-r--r-- | libffi/src/powerpc/aix_closure.S | 12 | ||||
-rw-r--r-- | libffi/src/powerpc/darwin_closure.S | 20 | ||||
-rw-r--r-- | libffi/src/powerpc/ffi_darwin.c | 318 | ||||
-rw-r--r-- | libffi/src/types.c | 2 |
4 files changed, 168 insertions, 184 deletions
diff --git a/libffi/src/powerpc/aix_closure.S b/libffi/src/powerpc/aix_closure.S index d0d50ca..bb5818b 100644 --- a/libffi/src/powerpc/aix_closure.S +++ b/libffi/src/powerpc/aix_closure.S @@ -105,8 +105,8 @@ ffi_closure_ASM: /* 24 Bytes (Linkage Area) */ /* 32 Bytes (params) */ - /* 104 Bytes (13*8 from FPR) */ - /* 8 Bytes (result) + /* 104 Bytes (13*8 from FPR) */ + /* 8 Bytes (result) */ /* 168 Bytes */ stwu r1,-176(r1) /* skip over caller save area @@ -144,20 +144,16 @@ ffi_closure_ASM: /* set up registers for the routine that actually does the work */ /* get the context pointer from the trampoline */ mr r3,r11 - + /* now load up the pointer to the result storage */ addi r4,r1,160 - + /* now load up the pointer to the saved gpr registers */ addi r5,r1,200 /* now load up the pointer to the saved fpr registers */ addi r6,r1,56 - /* now load up the pointer to the outgoing parameter */ - /* stack in the previous frame */ - addi r7,r1,232 - /* make the call */ bl .ffi_closure_helper_DARWIN nop diff --git a/libffi/src/powerpc/darwin_closure.S b/libffi/src/powerpc/darwin_closure.S index 9f721de..5dfa44b 100644 --- a/libffi/src/powerpc/darwin_closure.S +++ b/libffi/src/powerpc/darwin_closure.S @@ -31,7 +31,7 @@ .text .align 2 .globl _ffi_closure_ASM - + .text .align 2 _ffi_closure_ASM: @@ -44,13 +44,13 @@ LCFI0: 104 Bytes (13*8 from FPR) 8 Bytes (result) 168 Bytes */ - + stwu r1,-176(r1) /* skip over caller save area keep stack aligned to 16 */ LCFI1: /* we want to build up an area for the parameters passed in registers (both floating point and integer) */ - + /* we store gpr 3 to gpr 10 (aligned to 4) in the parents outgoing area */ stw r3, 200(r1) @@ -80,23 +80,19 @@ LCFI1: /* set up registers for the routine that actually does the work */ /* get the context pointer from the trampoline */ mr r3,r11 - + /* now load up the pointer to the result storage */ addi r4,r1,160 - + /* now load up the pointer to the saved gpr registers */ addi r5,r1,200 /* now load up the pointer to the saved fpr registers */ addi r6,r1,56 - /* now load up the pointer to the outgoing parameter - stack in the previous frame */ - addi r7,r1,232 - /* make the call */ bl Lffi_closure_helper_DARWIN$stub - + /* now r3 contains the return type */ /* so use it to look up in a table */ /* so we know how to deal with each type */ @@ -114,7 +110,7 @@ LFE1: /* Each of the ret_typeX code fragments has to be exactly 16 bytes long */ /* (4 instructions). For cache effectiveness we align to a 16 byte boundary */ /* first. */ - + .align 4 nop @@ -234,7 +230,7 @@ Lfinish: lwz r0,8(r1) /* get return address */ mtlr r0 /* reset link register */ blr - + /* END(ffi_closure_ASM) */ .data diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c index 3f70527..fee5243 100644 --- a/libffi/src/powerpc/ffi_darwin.c +++ b/libffi/src/powerpc/ffi_darwin.c @@ -29,7 +29,7 @@ #include <ffi_common.h> #include <stdlib.h> - + extern void ffi_closure_ASM(void); enum { @@ -81,8 +81,7 @@ enum { ASM_NEEDS_REGISTERS = 4 }; void ffi_prep_args(extended_cif *ecif, unsigned *const stack) /*@=exportheader@*/ { - const unsigned bytes = ecif->cif->bytes; - const unsigned flags = ecif->cif->flags; + const unsigned flags = ecif->cif->flags; /* 'stacktop' points at the previous backchain pointer. */ unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned)); @@ -96,12 +95,13 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack) /* 'next_arg' grows up as we put parameters in it. */ unsigned *next_arg = stack + 6; // 6 reserved posistions. - int i=ecif->cif->nargs; + int i = ecif->cif->nargs; double double_tmp; - float float_tmp; void **p_argv = ecif->avalue; unsigned gprvalue; ffi_type** ptr = ecif->cif->arg_types; + char *dest_cpy; + unsigned size_al = 0; /* Check that everything starts aligned properly. */ FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0); @@ -163,16 +163,29 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack) gprvalue = *(signed short *)*p_argv; goto putgpr; - case FFI_TYPE_STRUCT: + case FFI_TYPE_STRUCT: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_LONGDOUBLE: #endif - - memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size); - next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4); - break; - + dest_cpy = (char *) next_arg; + + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. + Structures with 3 byte in size are padded upwards. */ + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if ((*ptr)->elements[0]->type == 3) + size_al = ALIGN((*ptr)->size, 8); + if (size_al < 3 && ecif->cif->abi == FFI_DARWIN) + dest_cpy += 4 - size_al; + + memcpy((char *)dest_cpy, (char *)*p_argv, size_al); + next_arg += (size_al + 3) / 4; + break; + case FFI_TYPE_INT: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: @@ -187,7 +200,6 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack) } /* Check that we didn't overrun the stack... */ - //FFI_ASSERT(copy_space >= (char *)next_arg); //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS); //FFI_ASSERT((unsigned *)fpr_base // <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); @@ -203,7 +215,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) unsigned bytes; int fparg_count = 0, intarg_count = 0; unsigned flags = 0; - unsigned struct_copy_size = 0; + unsigned size_al = 0; /* All the machine-independent calculation of cif->bytes will be wrong. Redo the calculation for DARWIN. */ @@ -281,7 +293,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) on the stack. If they go on the stack, they must be 8-byte-aligned. */ if (intarg_count == NUM_GPR_ARG_REGISTERS-1 - || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0) + || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)) intarg_count++; intarg_count += 2; break; @@ -290,7 +302,13 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif - intarg_count+=(((*ptr)->size + 3) & ~0x3)/4; + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if ((*ptr)->elements[0]->type == 3) + size_al = ALIGN((*ptr)->size, 8); + intarg_count += (size_al + 3) / 4; break; default: @@ -303,9 +321,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) if (fparg_count != 0) flags |= FLAG_FP_ARGUMENTS; - if (struct_copy_size != 0) - flags |= FLAG_ARG_NEEDS_COPY; - + /* Space for the FPR registers, if needed. */ if (fparg_count != 0) bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); @@ -321,7 +337,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) cif->flags = flags; cif->bytes = bytes; - + return FFI_OK; } @@ -349,7 +365,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, ecif.cif = cif; ecif.avalue = avalue; - + /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ @@ -362,7 +378,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, } else ecif.rvalue = rvalue; - + switch (cif->abi) { case FFI_AIX: @@ -385,7 +401,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, static void flush_icache(char *); static void flush_range(char *, int); - + /* The layout of a function descriptor. A C function pointer really */ /* points to one of these. */ @@ -397,7 +413,7 @@ typedef struct aix_fd_struct { /* here I'd like to add the stack frame layout we use in darwin_closure.S * and aix_clsoure.S * -/* SP previous -> +---------------------------------------+ <--- child frame + * SP previous -> +---------------------------------------+ <--- child frame | back chain to caller 4 | +---------------------------------------+ 4 | saved CR 4 | @@ -441,7 +457,7 @@ SP current --> +---------------------------------------+ 176 <- parent frame | . | | r10 | +---------------------------------------+ 232 - | PST area, overflow part | + | overflow part | +---------------------------------------+ xxx | ???? | +---------------------------------------+ xxx @@ -456,7 +472,7 @@ ffi_prep_closure (ffi_closure* closure, unsigned int *tramp; struct ffi_aix_trampoline_struct *tramp_aix; aix_fd *fd; - + switch (cif->abi) { case FFI_DARWIN: @@ -464,24 +480,24 @@ ffi_prep_closure (ffi_closure* closure, FFI_ASSERT (cif->abi == FFI_DARWIN); tramp = (unsigned int *) &closure->tramp[0]; - tramp[0] = 0x7c0802a6; /* mflr r0 */ - tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ - tramp[4] = 0x7d6802a6; /* mflr r11 */ - tramp[5] = 0x818b0000; /* lwz r12,0(r11) /* function address */ - tramp[6] = 0x7c0803a6; /* mtlr r0 */ - tramp[7] = 0x7d8903a6; /* mtctr r12 */ - tramp[8] = 0x816b0004; /* lwz r11,4(r11) /* static chain */ - tramp[9] = 0x4e800420; /* bctr */ - *(void **) &tramp[2] = (void *)ffi_closure_ASM; /* function */ - *(void **) &tramp[3] = (void *)closure; /* context */ + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */ + tramp[6] = 0x7c0803a6; /* mtlr r0 */ + tramp[7] = 0x7d8903a6; /* mtctr r12 */ + tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */ + tramp[9] = 0x4e800420; /* bctr */ + tramp[2] = (unsigned long) ffi_closure_ASM; /* function */ + tramp[3] = (unsigned long) closure; /* context */ closure->cif = cif; closure->fun = fun; closure->user_data = user_data; - /* Flush the icache. Only necessary on Darwin */ + /* Flush the icache. Only necessary on Darwin. */ flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE); - + break; case FFI_AIX: @@ -530,8 +546,14 @@ flush_range(char * addr1, int size) flush_icache(addr1+size-1); } -int ffi_closure_helper_DARWIN (ffi_closure*, void*, unsigned long*, - unsigned long*, unsigned long*); +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int ffi_closure_helper_DARWIN (ffi_closure*, void*, + unsigned long*, ffi_dblfl*); /* Basically the trampoline invokes ffi_closure_ASM, and on * entry, r11 holds the address of the closure. @@ -541,15 +563,13 @@ int ffi_closure_helper_DARWIN (ffi_closure*, void*, unsigned long*, * following helper function to do most of the work */ -int -ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, - unsigned long * pgr, unsigned long * pfr, - unsigned long * pst) +int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, + unsigned long * pgr, ffi_dblfl * pfr) { - /* rvalue is the pointer to space for return value in closure assembly */ - /* pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM */ - /* pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM */ - /* pst is the pointer to outgoing parameter stack in original caller */ + /* rvalue is the pointer to space for return value in closure assembly + pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM + pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */ + void ** avalue; ffi_type ** arg_types; @@ -558,6 +578,7 @@ ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, long ng; /* number of general registers already used */ ffi_cif * cif; double temp; + unsigned size_al; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); @@ -569,9 +590,9 @@ ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, returns the data directly to the caller. */ if (cif->rtype->type == FFI_TYPE_STRUCT) { - rvalue = (void *)pgr; - ng++; + rvalue = (void *) *pgr; pgr++; + ng++; } i = 0; @@ -582,125 +603,97 @@ ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, while (i < avn) { switch (arg_types[i]->type) - { - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: - /* there are 8 gpr registers used to pass values */ - if (ng < 8) { - avalue[i] = (((char *)pgr)+3); - ng++; - pgr++; - } else { - avalue[i] = (((char *)pst)+3); - pst++; - } - break; - - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: - /* there are 8 gpr registers used to pass values */ - if (ng < 8) { - avalue[i] = (((char *)pgr)+2); - ng++; - pgr++; - } else { - avalue[i] = (((char *)pst)+2); - pst++; - } - break; - - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT32: - case FFI_TYPE_POINTER: - case FFI_TYPE_STRUCT: - /* there are 8 gpr registers used to pass values */ - if (ng < 8) { - avalue[i] = pgr; - ng++; - pgr++; - } else { - avalue[i] = pst; - pst++; - } - break; - - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - /* long long ints are passed in two gpr's if available or in - * the pst, one place is a bit odd, when a long long passes - * the boundary between gpr and pst area we have to increment - * the pst by one. - */ - if (ng < 7) { - avalue[i] = pgr; - ng+=2; - pgr+=2; - } else if (ng == 7) { - avalue[i] = pgr; - ng++; - pgr++; - pst++; - } else { - avalue[i] = pst; - pst+=2; - } - break; - - case FFI_TYPE_FLOAT: - /* a float value consumes a GPR - * - * there are 13 64bit floating point registers + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (char *) pgr + 3; + ng++; + pgr++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (char *) pgr + 2; + ng++; + pgr++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + avalue[i] = pgr; + ng++; + pgr++; + break; + + case FFI_TYPE_STRUCT: + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. */ + size_al = arg_types[i]->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if (arg_types[i]->elements[0]->type == 3) + size_al = ALIGN(arg_types[i]->size, 8); + if (size_al < 3 && cif->abi == FFI_DARWIN) + avalue[i] = (void*) pgr + 4 - size_al; + else + avalue[i] = (void*) pgr; + ng += (size_al + 3) / 4; + pgr += (size_al + 3) / 4; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Long long ints are passed in two gpr's. */ + avalue[i] = pgr; + ng += 2; + pgr += 2; + break; + + case FFI_TYPE_FLOAT: + /* a float value consumes a GPR + * + * here are 13 64bit floating point registers. */ - - if ((ng > 7) && (nf < 13)) { - pst++; - } - if (nf < 13) { - temp = *(double*)pfr; - *(float*)pfr = (float)temp; - avalue[i] = pfr; - nf++; - pfr+=2; - ng++; - pgr++; - - } else { - avalue[i] = pst; - nf++; - pst++; - } - break; - - case FFI_TYPE_DOUBLE: + if (nf < NUM_FPR_ARG_REGISTERS) + { + temp = pfr->d; + pfr->f = (float)temp; + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } + nf++; + ng++; + pgr++; + break; + + case FFI_TYPE_DOUBLE: /* a double value consumes two GPRs - * - * there are 13 64bit floating point registers + * + * There are 13 64bit floating point registers. */ - - if ((ng == 7) && (nf < 13)) { - pst++; /* if only one gpr is left the double steals it */ - } else if ((ng > 7) && (nf < 13)) { - pst+=2; /* a double consumes two GPRs in Darwin/AIX */ - } - if (nf < 13) { - avalue[i] = pfr; - nf++; - pfr+=2; - ng+=2; - pgr+=2; - - } else { - avalue[i] = pst; - nf++; - pst+=2; - } - break; + if (nf < NUM_FPR_ARG_REGISTERS) + { + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } + nf++; + ng += 2; + pgr += 2; + break; default: FFI_ASSERT(0); - } - i++; } @@ -708,5 +701,4 @@ ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, /* Tell ffi_closure_ASM to perform return type promotions. */ return cif->rtype->type; - } diff --git a/libffi/src/types.c b/libffi/src/types.c index 7d4d0a0..725df34 100644 --- a/libffi/src/types.c +++ b/libffi/src/types.c @@ -76,7 +76,7 @@ FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); -#elif defined ARM || defined SH || defined POWERPC64 +#elif defined ARM || defined SH || defined POWERPC64 || defined POWERPC_AIX || defined POWERPC_DARWIN FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); |