diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 61b0b4f43f4..483e483343c 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,17 @@ +2004-08-14 Casey Marshall + + * src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to + contain `FFI_TYPE_UINT64' as return type for any 64-bit + integer (O32 ABI only). + (ffi_prep_closure): new function. + (ffi_closure_mips_inner_O32): new function. + * src/mips/ffitarget.h: Define `FFI_CLOSURES' and + `FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32. + * src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return + 64 bit integers correctly. + (ffi_closure_O32): new function. + Added DWARF-2 unwind info for both functions. + 2004-08-10 Andrew Haley * src/x86/ffi64.c (ffi_prep_args ): 8-align all stack arguments. diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c index cc2078bc7e2..e12922aa046 100644 --- a/libffi/src/mips/ffi.c +++ b/libffi/src/mips/ffi.c @@ -27,6 +27,7 @@ #include #include +#include #if _MIPS_SIM == _ABIN32 #define FIX_ARGP \ @@ -314,6 +315,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) case FFI_TYPE_DOUBLE: cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); + break; default: cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); @@ -459,3 +465,117 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) break; } } + +#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */ +#if defined(FFI_MIPS_O32) +extern void ffi_closure_O32(void); +#endif /* FFI_MIPS_O32 */ + +ffi_status +ffi_prep_closure (ffi_closure *closure, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned int fn; + unsigned int ctx = (unsigned int) closure; + +#if defined(FFI_MIPS_O32) + FFI_ASSERT(cif->abi == FFI_O32); + fn = (unsigned int) ffi_closure_O32; +#else /* FFI_MIPS_N32 */ + FFI_ASSERT(cif->abi == FFI_N32); + FFI_ASSERT(!"not implemented"); +#endif /* FFI_MIPS_O32 */ + + tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */ + tramp[1] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */ + tramp[2] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */ + tramp[3] = 0x03200008; /* jr $25 */ + tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* XXX this is available on Linux, but anything else? */ + cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE); + + return FFI_OK; +} + +/* + * Decodes the arguments to a function, which will be stored on the + * stack. AR is the pointer to the beginning of the integer arguments + * (and, depending upon the arguments, some floating-point arguments + * as well). FPR is a pointer to the area where floating point + * registers have been saved, if any. + * + * RVALUE is the location where the function return value will be + * stored. CLOSURE is the prepared closure to invoke. + * + * This function should only be called from assembly, which is in + * turn called from a trampoline. + * + * Returns the function return type. + * + * Based on the similar routine for sparc. + */ +int +ffi_closure_mips_inner_O32 (ffi_closure *closure, + void *rvalue, unsigned long *ar, + double *fpr) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + int i, avn, argn, seen_int; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + + seen_int = 0; + argn = 0; + + if (cif->flags == FFI_TYPE_STRUCT) + { + rvalue = (void *) ar[0]; + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + if (i < 2 && !seen_int && + (arg_types[i]->type == FFI_TYPE_FLOAT || + arg_types[i]->type == FFI_TYPE_DOUBLE)) + { + avalue[i] = ((char *) &fpr[i]); + } + else + { + /* 8-byte arguments are always 8-byte aligned. */ + if (arg_types[i]->size == 8 && (argn & 0x1)) + argn++; + /* Float arguments take up two register slots. The float word + is the upper one. */ + if (argn == 2 && arg_types[i]->type == FFI_TYPE_FLOAT) + argn++; + avalue[i] = ((char *) &ar[argn]); + seen_int = 1; + } + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + return cif->rtype->type; +} + +#endif /* FFI_CLOSURES */ diff --git a/libffi/src/mips/ffitarget.h b/libffi/src/mips/ffitarget.h index 9378ed0da48..2e6fbaeec0a 100644 --- a/libffi/src/mips/ffitarget.h +++ b/libffi/src/mips/ffitarget.h @@ -153,7 +153,13 @@ typedef enum ffi_abi { /* ---- Definitions for closures ----------------------------------------- */ +#if defined(FFI_MIPS_O32) +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 20 +#else +/* N32/N64 not implemented yet. */ #define FFI_CLOSURES 0 +#endif /* FFI_MIPS_O32 */ #define FFI_NATIVE_RAW_API 0 #endif diff --git a/libffi/src/mips/o32.S b/libffi/src/mips/o32.S index 295095f1ed8..e2dfa8debdb 100644 --- a/libffi/src/mips/o32.S +++ b/libffi/src/mips/o32.S @@ -36,19 +36,24 @@ #define flags a3 #define SIZEOF_FRAME ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG ) +#define SIZEOF_FRAME2 ( 8 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG ) .text .align 2 .globl ffi_call_O32 .ent ffi_call_O32 ffi_call_O32: - +$LFB0: # Prologue SUBU $sp, SIZEOF_FRAME # Frame size +$LCFI0: REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer +$LCFI1: REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address +$LCFI2: move $fp, $sp +$LCFI3: move t9, callback # callback function pointer REG_S flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags @@ -136,12 +141,21 @@ call_it: REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) beqz t1, noretval - bne t2, FFI_TYPE_INT, retfloat + bne t2, FFI_TYPE_INT, retlonglong jal t9 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) REG_S v0, 0(t0) b epilogue +retlonglong: + # Really any 64-bit int, signed or not. + bne t2, FFI_TYPE_UINT64, retfloat + jal t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + REG_S v1, 4(t0) + REG_S v0, 0(t0) + b epilogue + retfloat: bne t2, FFI_TYPE_FLOAT, retdouble jal t9 @@ -167,6 +181,159 @@ epilogue: ADDU $sp, SIZEOF_FRAME # Fix stack pointer j ra +$LFE0: .end ffi_call_O32 - + + +/* ffi_closure_O32. Expects address of the passed-in ffi_closure + in t0. Stores any arguments passed in registers onto the + stack, then calls ffi_closure_mips_inner_O32, which + then decodes them. */ + + .text + .align 2 + .globl ffi_closure_O32 + .ent ffi_closure_O32 +ffi_closure_O32: +$LFB1: + # Prologue + .frame $fp, SIZEOF_FRAME2, $31 + .set noreorder + .cpload $25 + .set reorder + SUBU $sp, SIZEOF_FRAME2 + .cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG +$LCFI4: + REG_S $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer +$LCFI5: + REG_S ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Save return address +$LCFI6: + move $fp, $sp + +$LCFI7: + # Store all possible argument registers. If there are more than + # four arguments, then they should be stored above where we put $7. + REG_S $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp) + REG_S $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp) + REG_S $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp) + REG_S $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp) + + # Store all possible float/double registers. + s.d $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp) + s.d $f14, SIZEOF_FRAME2 - 8*FFI_SIZEOF_ARG($fp) + + # Call ffi_closure_mips_inner_O32 to do the work. + la $25, ffi_closure_mips_inner_O32 + move $4, $8 # Pointer to the ffi_closure + addu $5, $fp, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG + addu $6, $fp, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG + addu $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG + jal $31, $25 + + # Load the return value into the appropriate register. + move $8, $2 + li $9, FFI_TYPE_VOID + beq $8, $9, closure_done + + li $9, FFI_TYPE_FLOAT + l.s $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp) + beq $8, $9, closure_done + + li $9, FFI_TYPE_DOUBLE + l.d $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp) + beq $8, $9, closure_done + + li $9, FFI_TYPE_SINT64 + REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp) + beq $8, $9, integer + + li $9, FFI_TYPE_UINT64 + REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp) + beq $8, $9, integer + +integer: + REG_L $2, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp) + +closure_done: + # Epilogue + move $sp, $fp + REG_L $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer + REG_L ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME2 + j ra +$LFE1: + .end ffi_closure_O32 + +/* DWARF-2 unwind info. */ + + .section .eh_frame,"a",@progbits +$Lframe0: + .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry +$LSCIE0: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 4 # CIE Data Alignment Factor + .byte 0x1f # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1d + .uleb128 0x0 + .align 2 +$LECIE0: +$LSFDE0: + .4byte $LEFDE0-$LASFDE0 # FDE Length +$LASFDE0: + .4byte $LASFDE0-$Lframe0 # FDE CIE offset + .4byte $LFB0-. # FDE initial location + .4byte $LFE0-$LFB0 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI0-$LFB0 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x18 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI2-$LCFI0 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI3-$LCFI2 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x18 + .align 2 +$LEFDE0: +$LSFDE1: + .4byte $LEFDE1-$LASFDE1 # FDE Length +$LASFDE1: + .4byte $LASFDE1-$Lframe0 # FDE CIE offset + .4byte $LFB1-. # FDE initial location + .4byte $LFE1-$LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI4-$LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x28 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI6-$LCFI4 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI7-$LCFI6 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x28 + .align 2 +$LEFDE1: + #endif