From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15398 invoked by alias); 10 Oct 2014 20:43:57 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 15053 invoked by uid 89); 10 Oct 2014 20:43:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qa0-f48.google.com Received: from mail-qa0-f48.google.com (HELO mail-qa0-f48.google.com) (209.85.216.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 10 Oct 2014 20:43:49 +0000 Received: by mail-qa0-f48.google.com with SMTP id dc16so2198146qab.35 for ; Fri, 10 Oct 2014 13:43:47 -0700 (PDT) X-Received: by 10.229.29.3 with SMTP id o3mr12399466qcc.10.1412973827024; Fri, 10 Oct 2014 13:43:47 -0700 (PDT) Received: from anchor.com (50-194-63-110-static.hfc.comcastbusiness.net. [50.194.63.110]) by mx.google.com with ESMTPSA id s49sm5909008qge.15.2014.10.10.13.43.45 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Oct 2014 13:43:46 -0700 (PDT) From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: libffi-discuss@sourceware.org, gofrontend-dev@googlegroups.com Subject: [PATCH 13/13] libffi: Support go closures on i386 Date: Fri, 10 Oct 2014 20:43:00 -0000 Message-Id: <1412973773-3942-14-git-send-email-rth@redhat.com> In-Reply-To: <1412973773-3942-1-git-send-email-rth@redhat.com> References: <1412973773-3942-1-git-send-email-rth@redhat.com> X-IsSubscribed: yes X-SW-Source: 2014/txt/msg00107.txt.bz2 --- libffi/src/x86/ffi.c | 88 ++++++++++++++++++++++++++++++++++++----- libffi/src/x86/sysv.S | 107 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 166 insertions(+), 29 deletions(-) diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index e3f82ef..77abbe3 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -162,8 +162,9 @@ struct ffi_call_frame extern void ffi_call_i386(struct ffi_call_frame *, char *) FFI_HIDDEN __attribute__((fastcall)); -void -ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { size_t rsize; struct ffi_call_frame *frame; @@ -206,6 +207,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) frame->flags = flags; frame->rvalue = rvalue; + /* Install the closure as the static chain value. Note that the + static chain isn't part of an official ABI, it's what gcc itself + allocates for a given ABI. Generally, this is a register that's + predictably unused on entry. */ + switch (cabi) + { + case FFI_THISCALL: + case FFI_FASTCALL: + frame->eax = (unsigned)closure; + break; + default: + frame->ecx = (unsigned)closure; + break; + } + narg_reg = 0; switch (flags) { @@ -265,6 +281,20 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) ffi_call_i386(frame, stack); } +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); +} + + /* ------- Closure API support ----------------------------------- */ /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ @@ -321,18 +351,19 @@ ffi_prep_closure_loc (ffi_closure* closure, struct ffi_closure_frame { - unsigned rettemp[4]; /* 0 */ - unsigned eax; /* 16 */ - unsigned edx; /* 20 */ - unsigned ecx; /* 24 */ - ffi_closure *closure; /* 28 */ + unsigned rettemp[4]; /* 0 */ + unsigned eax; /* 16 */ + unsigned edx; /* 20 */ + unsigned ecx; /* 24 */ + ffi_cif *cif; /* 28 */ + void (*fun)(ffi_cif*,void*,void**,void*); /* 32 */ + void *user_data; /* 36 */ }; unsigned int FFI_HIDDEN __attribute__ ((fastcall)) ffi_closure_inner (struct ffi_closure_frame *frame, char *argp) { - ffi_closure *closure = frame->closure; - ffi_cif *cif = closure->cif; + ffi_cif *cif = frame->cif; int cabi, i, n, flags, narg_reg; ffi_type **arg_types; void *rvalue; @@ -389,7 +420,7 @@ ffi_closure_inner (struct ffi_closure_frame *frame, char *argp) avalue[i] = valp; } - closure->fun (cif, rvalue, avalue, closure->user_data); + frame->fun (cif, rvalue, avalue, frame->user_data); if (cabi == FFI_STDCALL) return flags + (cif->bytes << X86_RET_POP_SHIFT); @@ -559,4 +590,41 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue) ffi_call_i386(frame, stack); } +/* ------- Go API support ---------------------------------------- */ + +extern void ffi_go_closure_eax (void) FFI_HIDDEN; +extern void ffi_go_closure_ecx (void) FFI_HIDDEN; +extern void ffi_go_closure_stdcall (void) FFI_HIDDEN; + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + void (*dest)(void); + + /* See the comment in ffi_call_int about the static chain. */ + switch (cif->abi) + { + case FFI_SYSV: + case FFI_MS_CDECL: + dest = ffi_go_closure_ecx; + break; + case FFI_THISCALL: + case FFI_FASTCALL: + dest = ffi_go_closure_eax; + break; + case FFI_STDCALL: + dest = ffi_go_closure_stdcall; + break; + default: + return FFI_BAD_ABI; + } + + closure->tramp = dest; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + #endif /* !__x86_64__ */ diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S index d8256d0..2709b11 100644 --- a/libffi/src/x86/sysv.S +++ b/libffi/src/x86/sysv.S @@ -165,26 +165,37 @@ E X86_RET_UNUSED15 .cfi_endproc .size ffi_call_i386, . - ffi_call_i386 -/* The closure entry points are reached from the ffi_closure trampoline. - On entry, %eax contains the address of the ffi_closure. */ - -#define ffi_closure_FS (12 + 4*4 + 16) +#define ffi_closure_FS (4 + 3*4 + 3*4 + 16) -.macro FFI_CLOSURE_FIRST - subl $ffi_closure_FS, %esp - .cfi_adjust_cfa_offset ffi_closure_FS +/* Macros to help setting up the ffi_closure_data structure. */ - movl %edx, 20(%esp) /* save incoming register args */ +.macro FFI_CLOSURE_SAVE_REGS + movl %eax, 16(%esp) /* save incoming register args */ + movl %edx, 20(%esp) movl %ecx, 24(%esp) - movl %eax, 28(%esp) /* trampoline loaded closure */ +.endm + +.macro FFI_CLOSURE_COPY_TRAMP_DATA + movl 12(%eax), %edx /* copy cif */ + movl 16(%eax), %ecx /* copy fun */ + movl 20(%eax), %eax /* copy user_data */ + movl %edx, 28(%esp) + movl %ecx, 32(%esp) + movl %eax, 36(%esp) +.endm - movl %esp, %ecx /* pass save area to C */ - leal ffi_closure_FS+4(%esp), %edx +.macro FFI_CLOSURE_COPY_USER_DATA base, ofs, t1 + movl \ofs(\base), \t1 + movl \t1, 36(%esp) +.endm +.macro FFI_CLOSURE_CALL_INNER + movl %esp, %ecx /* load ffi_closure_data */ + leal ffi_closure_FS+4(%esp), %edx /* load incoming stack */ #ifdef __PIC__ - movl %ebx, 32(%esp) /* save ebx */ + movl %ebx, 40(%esp) /* save ebx */ .cfi_rel_offset %esp, 32 - call __x86.get_pc_thunk.bx + call __x86.get_pc_thunk.bx /* load got register */ addl $_GLOBAL_OFFSET_TABLE_, %ebx #endif #if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ @@ -194,11 +205,11 @@ E X86_RET_UNUSED15 #endif .endm -.macro FFI_CLOSURE_SECOND +.macro FFI_CLOSURE_MASK_AND_JUMP andl $X86_RET_TYPE_MASK, %eax #ifdef __PIC__ leal 0f@GOTOFF(%ebx, %eax, 8), %eax - movl 32(%esp), %ebx /* restore ebx */ + movl 40(%esp), %ebx /* restore ebx */ .cfi_restore %ebx #else leal 0f(, %eax, 8), %eax @@ -206,6 +217,36 @@ E X86_RET_UNUSED15 jmp *%eax .endm +/* The go closure entry points are called directly from Go code. + The suffix is the register in which the static chain is located. */ + + +.macro FFI_GO_CLOSURE suffix, chain, t1, t2 + .align 16 + .globl ffi_go_closure_\suffix + .type ffi_go_closure_\suffix, @function + FFI_HIDDEN (ffi_go_closure_\suffix) +ffi_go_closure_\suffix: + .cfi_startproc + subl $ffi_closure_FS, %esp + .cfi_adjust_cfa_offset ffi_closure_FS + FFI_CLOSURE_SAVE_REGS + movl 4(\chain), \t1 /* copy cif */ + movl 8(\chain), \t2 /* copy fun */ + movl \t1, 28(%esp) + movl \t2, 32(%esp) + movl \chain, 36(%esp) /* closure is user_data */ + jmp 88f + .cfi_endproc + .size ffi_go_closure_\suffix, . - ffi_go_closure_\suffix +.endm + +FFI_GO_CLOSURE eax, %eax, %edx, %ecx +FFI_GO_CLOSURE ecx, %ecx, %edx, %eax + +/* The closure entry points are reached from the ffi_closure trampoline. + On entry, %eax contains the address of the ffi_closure. */ + .align 16 .globl ffi_closure_i386 .type ffi_closure_i386, @function @@ -213,8 +254,16 @@ E X86_RET_UNUSED15 ffi_closure_i386: .cfi_startproc - FFI_CLOSURE_FIRST - FFI_CLOSURE_SECOND + subl $ffi_closure_FS, %esp + .cfi_adjust_cfa_offset ffi_closure_FS + + FFI_CLOSURE_SAVE_REGS + FFI_CLOSURE_COPY_TRAMP_DATA + +88: /* Entry point from preceeding Go closures. */ + + FFI_CLOSURE_CALL_INNER + FFI_CLOSURE_MASK_AND_JUMP .align 8 0: @@ -284,6 +333,8 @@ E X86_RET_UNUSED15 .cfi_endproc .size ffi_closure_i386, . - ffi_closure_i386 +FFI_GO_CLOSURE stdcall, %ecx, %edx, %eax + .align 16 .globl ffi_closure_i386_stdcall .type ffi_closure_i386_stdcall, @function @@ -291,16 +342,34 @@ E X86_RET_UNUSED15 ffi_closure_i386_stdcall: .cfi_startproc - FFI_CLOSURE_FIRST + subl $ffi_closure_FS, %esp + .cfi_adjust_cfa_offset ffi_closure_FS + + FFI_CLOSURE_SAVE_REGS + FFI_CLOSURE_COPY_TRAMP_DATA + +88: /* Entry point from preceeding Go closure. */ + + FFI_CLOSURE_CALL_INNER movl %eax, %ecx shrl $4, %ecx /* isolate pop count */ leal ffi_closure_FS(%esp, %ecx), %ecx /* compute popped esp */ movl ffi_closure_FS(%esp), %edx /* move return address */ movl %edx, (%ecx) + + /* New pseudo-stack frame based off ecx. This is unwind trickery + in that the CFA *has* changed, to the proper popped stack address. + Note that the location to which we moved the return address + is (the new) CFA-4, so that's unchanged. */ .cfi_def_cfa %ecx, 4 + /* Normally esp is unwound to CFA + the caller's ARGS_SIZE. + We've just set the CFA to that final value. Tell the unwinder + to restore esp from CFA without the ARGS_SIZE: + DW_CFA_val_expression %esp, DW_OP_call_frame_cfa. */ + .cfi_escape 0x16, 4, 1, 0x9c - FFI_CLOSURE_SECOND + FFI_CLOSURE_MASK_AND_JUMP .align 8 0: -- 1.9.3