summaryrefslogtreecommitdiff
path: root/debian/patches/libffi-mips.diff
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/libffi-mips.diff')
-rw-r--r--debian/patches/libffi-mips.diff703
1 files changed, 703 insertions, 0 deletions
diff --git a/debian/patches/libffi-mips.diff b/debian/patches/libffi-mips.diff
new file mode 100644
index 0000000..37b669a
--- /dev/null
+++ b/debian/patches/libffi-mips.diff
@@ -0,0 +1,703 @@
+# DP: Backport Mips go closure support, taken from libffi issue #197.
+
+--- a/src/libffi/src/mips/ffi.c
++++ b/src/libffi/src/mips/ffi.c
+@@ -581,14 +581,15 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ /* Low level routine for calling O32 functions */
+ extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+- unsigned, unsigned *, void (*)(void));
++ unsigned, unsigned *, void (*)(void), void *closure);
+
+ /* Low level routine for calling N32 functions */
+ extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+- unsigned, void *, void (*)(void));
++ unsigned, void *, void (*)(void), void *closure);
+
+-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
++void ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
++ void **avalue, void *closure)
+ {
+ extended_cif ecif;
+
+@@ -610,7 +611,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ case FFI_O32:
+ case FFI_O32_SOFT_FLOAT:
+ ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
+- cif->flags, ecif.rvalue, fn);
++ cif->flags, ecif.rvalue, fn, closure);
+ break;
+ #endif
+
+@@ -642,7 +643,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ #endif
+ }
+ ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
+- cif->flags, rvalue_copy, fn);
++ cif->flags, rvalue_copy, fn, closure);
+ if (copy_rvalue)
+ memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size);
+ }
+@@ -655,11 +656,27 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ }
+ }
+
++void
++ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
++{
++ ffi_call_int (cif, fn, rvalue, avalue, NULL);
++}
++
++void
++ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
++ void **avalue, void *closure)
++{
++ ffi_call_int (cif, fn, rvalue, avalue, closure);
++}
++
++
+ #if FFI_CLOSURES
+ #if defined(FFI_MIPS_O32)
+ extern void ffi_closure_O32(void);
++extern void ffi_go_closure_O32(void);
+ #else
+ extern void ffi_closure_N32(void);
++extern void ffi_go_closure_N32(void);
+ #endif /* FFI_MIPS_O32 */
+
+ ffi_status
+@@ -762,17 +779,17 @@ ffi_prep_closure_loc (ffi_closure *closure,
+ * Based on the similar routine for sparc.
+ */
+ int
+-ffi_closure_mips_inner_O32 (ffi_closure *closure,
++ffi_closure_mips_inner_O32 (ffi_cif *cif,
++ void (*fun)(ffi_cif*, void*, void**, void*),
++ void *user_data,
+ void *rvalue, ffi_arg *ar,
+ double *fpr)
+ {
+- ffi_cif *cif;
+ void **avaluep;
+ ffi_arg *avalue;
+ ffi_type **arg_types;
+ int i, avn, argn, seen_int;
+
+- cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (ffi_arg));
+ avaluep = alloca (cif->nargs * sizeof (ffi_arg));
+
+@@ -840,7 +857,7 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
+ }
+
+ /* Invoke the closure. */
+- (closure->fun) (cif, rvalue, avaluep, closure->user_data);
++ fun(cif, rvalue, avaluep, user_data);
+
+ if (cif->abi == FFI_O32_SOFT_FLOAT)
+ {
+@@ -916,11 +933,12 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
+ *
+ */
+ int
+-ffi_closure_mips_inner_N32 (ffi_closure *closure,
++ffi_closure_mips_inner_N32 (ffi_cif *cif,
++ void (*fun)(ffi_cif*, void*, void**, void*),
++ void *user_data,
+ void *rvalue, ffi_arg *ar,
+ ffi_arg *fpr)
+ {
+- ffi_cif *cif;
+ void **avaluep;
+ ffi_arg *avalue;
+ ffi_type **arg_types;
+@@ -928,7 +946,6 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
+ int soft_float;
+ ffi_arg *argp;
+
+- cif = closure->cif;
+ soft_float = cif->abi == FFI_N64_SOFT_FLOAT
+ || cif->abi == FFI_N32_SOFT_FLOAT;
+ avalue = alloca (cif->nargs * sizeof (ffi_arg));
+@@ -1040,11 +1057,49 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
+ }
+
+ /* Invoke the closure. */
+- (closure->fun) (cif, rvalue, avaluep, closure->user_data);
++ fun (cif, rvalue, avaluep, user_data);
+
+ return cif->flags >> (FFI_FLAG_BITS * 8);
+ }
+
+ #endif /* FFI_MIPS_N32 */
+
++#if defined(FFI_MIPS_O32)
++extern void ffi_closure_O32(void);
++extern void ffi_go_closure_O32(void);
++#else
++extern void ffi_closure_N32(void);
++extern void ffi_go_closure_N32(void);
++#endif /* FFI_MIPS_O32 */
++
++ffi_status
++ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
++ void (*fun)(ffi_cif*,void*,void**,void*))
++{
++ void * fn;
++
++#if defined(FFI_MIPS_O32)
++ if (cif->abi != FFI_O32 && cif->abi != FFI_O32_SOFT_FLOAT)
++ return FFI_BAD_ABI;
++ fn = ffi_go_closure_O32;
++#else
++#if _MIPS_SIM ==_ABIN32
++ if (cif->abi != FFI_N32
++ && cif->abi != FFI_N32_SOFT_FLOAT)
++ return FFI_BAD_ABI;
++#else
++ if (cif->abi != FFI_N64
++ && cif->abi != FFI_N64_SOFT_FLOAT)
++ return FFI_BAD_ABI;
++#endif
++ fn = ffi_go_closure_N32;
++#endif /* FFI_MIPS_O32 */
++
++ closure->tramp = (void *)fn;
++ closure->cif = cif;
++ closure->fun = fun;
++
++ return FFI_OK;
++}
++
+ #endif /* FFI_CLOSURES */
+--- a/src/libffi/src/mips/ffitarget.h
++++ b/src/libffi/src/mips/ffitarget.h
+@@ -231,12 +231,14 @@ typedef enum ffi_abi {
+
+ #if defined(FFI_MIPS_O32)
+ #define FFI_CLOSURES 1
++#define FFI_GO_CLOSURES 1
+ #define FFI_TRAMPOLINE_SIZE 20
+ #else
+ /* N32/N64. */
+ # define FFI_CLOSURES 1
++#define FFI_GO_CLOSURES 1
+ #if _MIPS_SIM==_ABI64
+-#define FFI_TRAMPOLINE_SIZE 52
++#define FFI_TRAMPOLINE_SIZE 56
+ #else
+ #define FFI_TRAMPOLINE_SIZE 20
+ #endif
+--- a/src/libffi/src/mips/n32.S
++++ b/src/libffi/src/mips/n32.S
+@@ -37,8 +37,12 @@
+ #define flags a3
+ #define raddr a4
+ #define fn a5
++#define closure a6
+
+-#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
++/* Note: to keep stack 16 byte aligned we need even number slots
++ used 9 slots here
++*/
++#define SIZEOF_FRAME ( 10 * FFI_SIZEOF_ARG )
+
+ #ifdef __GNUC__
+ .abicalls
+@@ -49,24 +53,25 @@
+ .globl ffi_call_N32
+ .ent ffi_call_N32
+ ffi_call_N32:
+-.LFB3:
++.LFB0:
+ .frame $fp, SIZEOF_FRAME, ra
+ .mask 0xc0000000,-FFI_SIZEOF_ARG
+ .fmask 0x00000000,0
+
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+-.LCFI0:
++.LCFI00:
+ REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+ REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+-.LCFI1:
++.LCFI01:
+ move $fp, $sp
+-.LCFI3:
++.LCFI02:
+ move t9, callback # callback function pointer
+ REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
+ REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
+ REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
+ REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
++ REG_S closure, 6*FFI_SIZEOF_ARG($fp) # closure
+
+ # Allocate at least 4 words in the argstack
+ move v0, bytes
+@@ -198,6 +203,9 @@ callit:
+ # Load the function pointer
+ REG_L t9, 5*FFI_SIZEOF_ARG($fp)
+
++ # install the static chain(t7=$15)
++ REG_L t7, 6*FFI_SIZEOF_ARG($fp)
++
+ # If the return value pointer is NULL, assume no return value.
+ REG_L t5, 4*FFI_SIZEOF_ARG($fp)
+ beqz t5, noretval
+@@ -346,7 +354,7 @@ epilogue:
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
+ j ra
+
+-.LFE3:
++.LFE0:
+ .end ffi_call_N32
+
+ /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
+@@ -406,6 +414,41 @@ epilogue:
+ #define GP_OFF2 (0 * FFI_SIZEOF_ARG)
+
+ .align 2
++ .globl ffi_go_closure_N32
++ .ent ffi_go_closure_N32
++ffi_go_closure_N32:
++.LFB1:
++ .frame $sp, SIZEOF_FRAME2, ra
++ .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
++ .fmask 0x00000000,0
++ SUBU $sp, SIZEOF_FRAME2
++.LCFI10:
++ .cpsetup t9, GP_OFF2, ffi_go_closure_N32
++ REG_S ra, RA_OFF2($sp) # Save return address
++.LCFI11:
++
++ REG_S a0, A0_OFF2($sp)
++ REG_S a1, A1_OFF2($sp)
++ REG_S a2, A2_OFF2($sp)
++ REG_S a3, A3_OFF2($sp)
++ REG_S a4, A4_OFF2($sp)
++ REG_S a5, A5_OFF2($sp)
++
++ # Call ffi_closure_mips_inner_N32 to do the real work.
++ LA t9, ffi_closure_mips_inner_N32
++ REG_L a0, 8($15) # cif
++ REG_L a1, 16($15) # fun
++ move a2, t7 # userdata=closure
++ ADDU a3, $sp, V0_OFF2 # rvalue
++ ADDU a4, $sp, A0_OFF2 # ar
++ ADDU a5, $sp, F12_OFF2 # fpr
++
++ b $do_closure
++
++.LFE1:
++ .end ffi_go_closure_N32
++
++ .align 2
+ .globl ffi_closure_N32
+ .ent ffi_closure_N32
+ ffi_closure_N32:
+@@ -414,18 +457,29 @@ ffi_closure_N32:
+ .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
+ .fmask 0x00000000,0
+ SUBU $sp, SIZEOF_FRAME2
+-.LCFI5:
++.LCFI20:
+ .cpsetup t9, GP_OFF2, ffi_closure_N32
+ REG_S ra, RA_OFF2($sp) # Save return address
+-.LCFI6:
+- # Store all possible argument registers. If there are more than
+- # fit in registers, then they were stored on the stack.
++.LCFI21:
+ REG_S a0, A0_OFF2($sp)
+ REG_S a1, A1_OFF2($sp)
+ REG_S a2, A2_OFF2($sp)
+ REG_S a3, A3_OFF2($sp)
+ REG_S a4, A4_OFF2($sp)
+ REG_S a5, A5_OFF2($sp)
++
++ # Call ffi_closure_mips_inner_N32 to do the real work.
++ LA t9, ffi_closure_mips_inner_N32
++ REG_L a0, 56($12) # cif
++ REG_L a1, 64($12) # fun
++ REG_L a2, 72($12) # user_data
++ ADDU a3, $sp, V0_OFF2
++ ADDU a4, $sp, A0_OFF2
++ ADDU a5, $sp, F12_OFF2
++
++$do_closure:
++ # Store all possible argument registers. If there are more than
++ # fit in registers, then they were stored on the stack.
+ REG_S a6, A6_OFF2($sp)
+ REG_S a7, A7_OFF2($sp)
+
+@@ -439,12 +493,6 @@ ffi_closure_N32:
+ s.d $f18, F18_OFF2($sp)
+ s.d $f19, F19_OFF2($sp)
+
+- # Call ffi_closure_mips_inner_N32 to do the real work.
+- LA t9, ffi_closure_mips_inner_N32
+- move a0, $12 # Pointer to the ffi_closure
+- ADDU a1, $sp, V0_OFF2
+- ADDU a2, $sp, A0_OFF2
+- ADDU a3, $sp, F12_OFF2
+ jalr t9
+
+ # Return flags are in v0
+@@ -531,46 +579,66 @@ cls_epilogue:
+ .align EH_FRAME_ALIGN
+ .LECIE1:
+
+-.LSFDE1:
+- .4byte .LEFDE1-.LASFDE1 # length.
+-.LASFDE1:
+- .4byte .LASFDE1-.Lframe1 # CIE_pointer.
+- FDE_ADDR_BYTES .LFB3 # initial_location.
+- FDE_ADDR_BYTES .LFE3-.LFB3 # address_range.
++.LSFDE0:
++ .4byte .LEFDE0-.LASFDE0 # length.
++.LASFDE0:
++ .4byte .LASFDE0-.Lframe1 # CIE_pointer.
++ FDE_ADDR_BYTES .LFB0 # initial_location.
++ FDE_ADDR_BYTES .LFE0-.LFB0 # address_range.
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte .LCFI0-.LFB3 # to .LCFI0
++ .4byte .LCFI00-.LFB0 # to .LCFI00
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte .LCFI1-.LCFI0 # to .LCFI1
++ .4byte .LCFI01-.LCFI00 # to .LCFI01
+ .byte 0x9e # DW_CFA_offset of $fp
+ .uleb128 2*FFI_SIZEOF_ARG/4 #
+ .byte 0x9f # DW_CFA_offset of ra
+ .uleb128 1*FFI_SIZEOF_ARG/4 #
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte .LCFI3-.LCFI1 # to .LCFI3
++ .4byte .LCFI02-.LCFI01 # to .LCFI02
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0x1e # in $fp
+ .align EH_FRAME_ALIGN
++.LEFDE0:
++
++.LSFDE1:
++ .4byte .LEFDE1-.LASFDE1 # length
++.LASFDE1:
++ .4byte .LASFDE1-.Lframe1 # CIE_pointer.
++ FDE_ADDR_BYTES .LFB1 # initial_location.
++ FDE_ADDR_BYTES .LFE1-.LFB1 # address_range.
++ .byte 0x4 # DW_CFA_advance_loc4
++ .4byte .LCFI10-.LFB1 # to .LCFI10
++ .byte 0xe # DW_CFA_def_cfa_offset
++ .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
++ .byte 0x4 # DW_CFA_advance_loc4
++ .4byte .LCFI11-.LCFI10 # to .LCFI11
++ .byte 0x9c # DW_CFA_offset of $gp ($28)
++ .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
++ .byte 0x9f # DW_CFA_offset of ra ($31)
++ .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
++ .align EH_FRAME_ALIGN
+ .LEFDE1:
+-.LSFDE3:
+- .4byte .LEFDE3-.LASFDE3 # length
+-.LASFDE3:
+- .4byte .LASFDE3-.Lframe1 # CIE_pointer.
++
++.LSFDE2:
++ .4byte .LEFDE2-.LASFDE2 # length
++.LASFDE2:
++ .4byte .LASFDE2-.Lframe1 # CIE_pointer.
+ FDE_ADDR_BYTES .LFB2 # initial_location.
+ FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte .LCFI5-.LFB2 # to .LCFI5
++ .4byte .LCFI20-.LFB2 # to .LCFI20
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte .LCFI6-.LCFI5 # to .LCFI6
++ .4byte .LCFI21-.LCFI20 # to .LCFI21
+ .byte 0x9c # DW_CFA_offset of $gp ($28)
+ .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
+ .byte 0x9f # DW_CFA_offset of ra ($31)
+ .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
+ .align EH_FRAME_ALIGN
+-.LEFDE3:
++.LEFDE2:
+ #endif /* __GNUC__ */
+
+ #endif
+--- a/src/libffi/src/mips/o32.S
++++ b/src/libffi/src/mips/o32.S
+@@ -50,14 +50,14 @@ ffi_call_O32:
+ $LFB0:
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+-$LCFI0:
++$LCFI00:
+ REG_S $fp, FP_OFF($sp) # Save frame pointer
+-$LCFI1:
++$LCFI01:
+ REG_S ra, RA_OFF($sp) # Save return address
+-$LCFI2:
++$LCFI02:
+ move $fp, $sp
+
+-$LCFI3:
++$LCFI03:
+ move t9, callback # callback function pointer
+ REG_S flags, A3_OFF($fp) # flags
+
+@@ -132,6 +132,9 @@ pass_f_d:
+ l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+
+ call_it:
++ # Load the static chain pointer
++ REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp)
++
+ # Load the function pointer
+ REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
+
+@@ -204,13 +207,15 @@ $LFE0:
+ -8 - f14 (le low, be high)
+ -9 - f12 (le high, be low)
+ -10 - f12 (le low, be high)
+- -11 - Called function a3 save
+- -12 - Called function a2 save
+- -13 - Called function a1 save
+- -14 - Called function a0 save, our sp and fp point here
++ -11 - Called function a5 save
++ -12 - Called function a4 save
++ -13 - Called function a3 save
++ -14 - Called function a2 save
++ -15 - Called function a1 save
++ -16 - Called function a0 save, our sp and fp point here
+ */
+
+-#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
++#define SIZEOF_FRAME2 (16 * FFI_SIZEOF_ARG)
+ #define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
+ #define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
+ #define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
+@@ -225,13 +230,71 @@ $LFE0:
+ #define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
+ #define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
+ #define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
++#define CALLED_A5_OFF2 (SIZEOF_FRAME2 - 11 * FFI_SIZEOF_ARG)
++#define CALLED_A4_OFF2 (SIZEOF_FRAME2 - 12 * FFI_SIZEOF_ARG)
+
+ .text
++
++ .align 2
++ .globl ffi_go_closure_O32
++ .ent ffi_go_closure_O32
++ffi_go_closure_O32:
++$LFB1:
++ # Prologue
++ .frame $fp, SIZEOF_FRAME2, ra
++ .set noreorder
++ .cpload t9
++ .set reorder
++ SUBU $sp, SIZEOF_FRAME2
++ .cprestore GP_OFF2
++$LCFI10:
++
++ REG_S $16, S0_OFF2($sp) # Save s0
++ REG_S $fp, FP_OFF2($sp) # Save frame pointer
++ REG_S ra, RA_OFF2($sp) # Save return address
++$LCFI11:
++
++ move $fp, $sp
++$LCFI12:
++
++ REG_S a0, A0_OFF2($fp)
++ REG_S a1, A1_OFF2($fp)
++ REG_S a2, A2_OFF2($fp)
++ REG_S a3, A3_OFF2($fp)
++
++ # Load ABI enum to s0
++ REG_L $16, 4($15) # cif
++ REG_L $16, 0($16) # abi is first member.
++
++ li $13, 1 # FFI_O32
++ bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
++
++ # Store all possible float/double registers.
++ s.d $f12, FA_0_0_OFF2($fp)
++ s.d $f14, FA_1_0_OFF2($fp)
++1:
++ # prepare arguments for ffi_closure_mips_inner_O32
++ REG_L a0, 4($15) # cif
++ REG_L a1, 8($15) # fun
++ move a2, $15 # user_data = go closure
++ addu a3, $fp, V0_OFF2 # rvalue
++
++ addu t9, $fp, A0_OFF2 # ar
++ REG_S t9, CALLED_A4_OFF2($fp)
++
++ addu t9, $fp, FA_0_0_OFF2 #fpr
++ REG_S t9, CALLED_A5_OFF2($fp)
++
++ b $do_closure
++
++$LFE1:
++ .end ffi_go_closure_O32
++
+ .align 2
+ .globl ffi_closure_O32
+ .ent ffi_closure_O32
+ ffi_closure_O32:
+-$LFB1:
++$LFB2:
+ # Prologue
+ .frame $fp, SIZEOF_FRAME2, ra
+ .set noreorder
+@@ -239,14 +302,14 @@ $LFB1:
+ .set reorder
+ SUBU $sp, SIZEOF_FRAME2
+ .cprestore GP_OFF2
+-$LCFI4:
++$LCFI20:
+ REG_S $16, S0_OFF2($sp) # Save s0
+ REG_S $fp, FP_OFF2($sp) # Save frame pointer
+ REG_S ra, RA_OFF2($sp) # Save return address
+-$LCFI6:
++$LCFI21:
+ move $fp, $sp
+
+-$LCFI7:
++$LCFI22:
+ # Store all possible argument registers. If there are more than
+ # four arguments, then they are stored above where we put a3.
+ REG_S a0, A0_OFF2($fp)
+@@ -265,12 +328,21 @@ $LCFI7:
+ s.d $f12, FA_0_0_OFF2($fp)
+ s.d $f14, FA_1_0_OFF2($fp)
+ 1:
+- # Call ffi_closure_mips_inner_O32 to do the work.
++ # prepare arguments for ffi_closure_mips_inner_O32
++ REG_L a0, 20($12) # cif pointer follows tramp.
++ REG_L a1, 24($12) # fun
++ REG_L a2, 28($12) # user_data
++ addu a3, $fp, V0_OFF2 # rvalue
++
++ addu t9, $fp, A0_OFF2 # ar
++ REG_S t9, CALLED_A4_OFF2($fp)
++
++ addu t9, $fp, FA_0_0_OFF2 #fpr
++ REG_S t9, CALLED_A5_OFF2($fp)
++
++$do_closure:
+ la t9, ffi_closure_mips_inner_O32
+- move a0, $12 # Pointer to the ffi_closure
+- addu a1, $fp, V0_OFF2
+- addu a2, $fp, A0_OFF2
+- addu a3, $fp, FA_0_0_OFF2
++ # Call ffi_closure_mips_inner_O32 to do the work.
+ jalr t9
+
+ # Load the return value into the appropriate register.
+@@ -300,7 +372,7 @@ closure_done:
+ REG_L ra, RA_OFF2($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME2
+ j ra
+-$LFE1:
++$LFE2:
+ .end ffi_closure_O32
+
+ /* DWARF-2 unwind info. */
+@@ -322,6 +394,7 @@ $LSCIE0:
+ .uleb128 0x0
+ .align 2
+ $LECIE0:
++
+ $LSFDE0:
+ .4byte $LEFDE0-$LASFDE0 # FDE Length
+ $LASFDE0:
+@@ -330,11 +403,11 @@ $LASFDE0:
+ .4byte $LFE0-$LFB0 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI0-$LFB0
++ .4byte $LCFI00-$LFB0
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x18
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI2-$LCFI0
++ .4byte $LCFI01-$LCFI00
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+@@ -342,12 +415,13 @@ $LASFDE0:
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI3-$LCFI2
++ .4byte $LCFI02-$LCFI01
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 0x18
+ .align 2
+ $LEFDE0:
++
+ $LSFDE1:
+ .4byte $LEFDE1-$LASFDE1 # FDE Length
+ $LASFDE1:
+@@ -356,11 +430,11 @@ $LASFDE1:
+ .4byte $LFE1-$LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI4-$LFB1
++ .4byte $LCFI10-$LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+- .uleb128 0x38
++ .uleb128 SIZEOF_FRAME2
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI6-$LCFI4
++ .4byte $LCFI11-$LCFI10
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x10 # $16
+ .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
+@@ -371,11 +445,41 @@ $LASFDE1:
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+- .4byte $LCFI7-$LCFI6
++ .4byte $LCFI12-$LCFI11
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+- .uleb128 0x38
++ .uleb128 SIZEOF_FRAME2
+ .align 2
+ $LEFDE1:
+
++$LSFDE2:
++ .4byte $LEFDE2-$LASFDE2 # FDE Length
++$LASFDE2:
++ .4byte $LASFDE2-$Lframe0 # FDE CIE offset
++ .4byte $LFB2 # FDE initial location
++ .4byte $LFE2-$LFB2 # FDE address range
++ .uleb128 0x0 # Augmentation size
++ .byte 0x4 # DW_CFA_advance_loc4
++ .4byte $LCFI20-$LFB2
++ .byte 0xe # DW_CFA_def_cfa_offset
++ .uleb128 SIZEOF_FRAME2
++ .byte 0x4 # DW_CFA_advance_loc4
++ .4byte $LCFI21-$LCFI20
++ .byte 0x11 # DW_CFA_offset_extended_sf
++ .uleb128 0x10 # $16
++ .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
++ .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 $LCFI22-$LCFI21
++ .byte 0xc # DW_CFA_def_cfa
++ .uleb128 0x1e
++ .uleb128 SIZEOF_FRAME2
++ .align 2
++$LEFDE2:
++
+ #endif