From c8e82d9fbffd3eeaef0266a1aac64d7bd13ee9c3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 26 Jul 2015 16:18:57 -0700 Subject: [PATCH 1/4] src/x86/win64.S: Support compiling on non-WIN64 platforms Non-WIN64 versions of the GNU assembler don't support the .seh_* directives for structured exception handling, so wrap them in a macro that compiles to nothing. Handle the registers used for the non-Windows x86-64 calling convention when on a non-Windows platform. Distinguish between cases that should refer to the native argument registers (defined as arg0, arg1, arg2, and arg3) and cases that should always refer to the Windows argument registers. --- src/x86/win64.S | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/x86/win64.S b/src/x86/win64.S index a5a20b64..eed57c21 100644 --- a/src/x86/win64.S +++ b/src/x86/win64.S @@ -7,10 +7,19 @@ .cfi_sections .debug_frame #endif +#ifdef X86_WIN64 +#define SEH(...) __VA_ARGS__ #define arg0 %rcx #define arg1 %rdx #define arg2 %r8 #define arg3 %r9 +#else +#define SEH(...) +#define arg0 %rdi +#define arg1 %rsi +#define arg2 %rdx +#define arg3 %rcx +#endif #ifdef SYMBOL_UNDERSCORE #define SYMBOL_NAME(name) _##name @@ -34,7 +43,7 @@ .align 8 .globl ffi_call_win64 - .seh_proc ffi_call_win64 + SEH(.seh_proc ffi_call_win64) ffi_call_win64: cfi_startproc /* Set up the local stack frame and install it in rbp/rsp. */ @@ -44,9 +53,9 @@ ffi_call_win64: movq arg1, %rbp cfi_def_cfa(%rbp, 16) cfi_rel_offset(%rbp, 0) - .seh_pushreg %rbp - .seh_setframe %rbp, 0 - .seh_endprologue + SEH(.seh_pushreg %rbp) + SEH(.seh_setframe %rbp, 0) + SEH(.seh_endprologue) movq arg0, %rsp movq arg2, %r10 @@ -149,7 +158,7 @@ E FFI_TYPE_SMALL_STRUCT_4B .purgem epilogue cfi_endproc - .seh_endproc + SEH(.seh_endproc) /* 32 bytes of outgoing register stack space, 8 bytes of alignment, @@ -161,33 +170,33 @@ E FFI_TYPE_SMALL_STRUCT_4B .align 8 .globl ffi_go_closure_win64 - .seh_proc ffi_go_closure_win64 + SEH(.seh_proc ffi_go_closure_win64) ffi_go_closure_win64: cfi_startproc /* Save all integer arguments into the incoming reg stack space. */ - movq arg0, 8(%rsp) - movq arg1, 16(%rsp) - movq arg2, 24(%rsp) - movq arg3, 32(%rsp) + movq %rcx, 8(%rsp) + movq %rdx, 16(%rsp) + movq %r8, 24(%rsp) + movq %r9, 32(%rsp) movq 8(%r10), arg0 /* load cif */ movq 16(%r10), arg1 /* load fun */ movq %r10, arg2 /* closure is user_data */ jmp 0f cfi_endproc - .seh_endproc + SEH(.seh_endproc) .align 8 .globl ffi_closure_win64 - .seh_proc ffi_closure_win64 + SEH(.seh_proc ffi_closure_win64) ffi_closure_win64: cfi_startproc /* Save all integer arguments into the incoming reg stack space. */ - movq arg0, 8(%rsp) - movq arg1, 16(%rsp) - movq arg2, 24(%rsp) - movq arg3, 32(%rsp) + movq %rcx, 8(%rsp) + movq %rdx, 16(%rsp) + movq %r8, 24(%rsp) + movq %r9, 32(%rsp) movq FFI_TRAMPOLINE_SIZE(%r10), arg0 /* load cif */ movq FFI_TRAMPOLINE_SIZE+8(%r10), arg1 /* load fun */ @@ -195,8 +204,8 @@ ffi_closure_win64: 0: subq $ffi_clo_FS, %rsp cfi_adjust_cfa_offset(ffi_clo_FS) - .seh_stackalloc ffi_clo_FS - .seh_endprologue + SEH(.seh_stackalloc ffi_clo_FS) + SEH(.seh_endprologue) /* Save all sse arguments into the stack frame. */ movsd %xmm0, ffi_clo_OFF_X(%rsp) @@ -216,4 +225,4 @@ ffi_closure_win64: ret cfi_endproc - .seh_endproc + SEH(.seh_endproc) From eaa59755fcbb692a8cb763c7f9f24a350aadbd30 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 26 Jul 2015 17:17:16 -0700 Subject: [PATCH 2/4] src/x86/win64.S: Handle name mangling and PIC Move the macros from unix64.S into a shared header asmnames.h and use them in win64.S too. --- src/x86/asmnames.h | 30 ++++++++++++++++++++++++++++++ src/x86/unix64.S | 23 +---------------------- src/x86/win64.S | 13 ++++--------- 3 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 src/x86/asmnames.h diff --git a/src/x86/asmnames.h b/src/x86/asmnames.h new file mode 100644 index 00000000..7551021e --- /dev/null +++ b/src/x86/asmnames.h @@ -0,0 +1,30 @@ +#ifndef ASMNAMES_H +#define ASMNAMES_H + +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) +#ifdef __USER_LABEL_PREFIX__ +# define C(X) C1(__USER_LABEL_PREFIX__, X) +#else +# define C(X) X +#endif + +#ifdef __APPLE__ +# define L(X) C1(L, X) +#else +# define L(X) C1(.L, X) +#endif + +#if defined(__ELF__) && defined(__PIC__) +# define PLT(X) X@PLT +#else +# define PLT(X) X +#endif + +#ifdef __ELF__ +# define ENDF(X) .type X,@function; .size X, . - X +#else +# define ENDF(X) +#endif + +#endif /* ASMNAMES_H */ diff --git a/src/x86/unix64.S b/src/x86/unix64.S index c83010c7..129aba50 100644 --- a/src/x86/unix64.S +++ b/src/x86/unix64.S @@ -31,31 +31,10 @@ #include #include #include "internal64.h" +#include "asmnames.h" .text -#define C2(X, Y) X ## Y -#define C1(X, Y) C2(X, Y) -#ifdef __USER_LABEL_PREFIX__ -# define C(X) C1(__USER_LABEL_PREFIX__, X) -#else -# define C(X) X -#endif - -#ifdef __APPLE__ -# define L(X) C1(L, X) -#else -# define L(X) C1(.L, X) -#endif - -#ifdef __ELF__ -# define PLT(X) X@PLT -# define ENDF(X) .type X,@function; .size X, . - X -#else -# define PLT(X) X -# define ENDF(X) -#endif - /* This macro allows the safe creation of jump tables without an actual table. The entry points into the table are all 8 bytes. The use of ORG asserts that we're at the correct location. */ diff --git a/src/x86/win64.S b/src/x86/win64.S index eed57c21..9d4f8b95 100644 --- a/src/x86/win64.S +++ b/src/x86/win64.S @@ -2,6 +2,7 @@ #include #include #include +#include "asmnames.h" #if defined(HAVE_AS_CFI_PSEUDO_OP) .cfi_sections .debug_frame @@ -21,12 +22,6 @@ #define arg3 %rcx #endif -#ifdef SYMBOL_UNDERSCORE -#define SYMBOL_NAME(name) _##name -#else -#define SYMBOL_NAME(name) name -#endif - .macro E which .align 8 .org 0b + \which * 8 @@ -106,7 +101,7 @@ E FFI_TYPE_DOUBLE movsd %xmm0, (%r8) epilogue E FFI_TYPE_LONGDOUBLE - call abort + call PLT(C(abort)) E FFI_TYPE_UINT8 movzbl %al, %eax movq %rax, (%r8) @@ -141,7 +136,7 @@ E FFI_TYPE_POINTER movq %rax, (%r8) epilogue E FFI_TYPE_COMPLEX - call abort + call PLT(C(abort)) E FFI_TYPE_SMALL_STRUCT_1B movb %al, (%r8) epilogue @@ -153,7 +148,7 @@ E FFI_TYPE_SMALL_STRUCT_4B epilogue .align 8 -99: call abort +99: call PLT(C(abort)) .purgem epilogue From 6de51f3e04e496901ea1bd8f9b44f75c9f01b599 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 26 Jul 2015 16:23:55 -0700 Subject: [PATCH 3/4] src/x86/ffiw64.c: Don't assign a "char *" to an "unsigned char *" Declare a local variable to match the type of the struct field assigned to it, rather than adding unsigned to the type. Fixes a -Wpointer-sign warning. --- src/x86/ffiw64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86/ffiw64.c b/src/x86/ffiw64.c index 8a33a6c4..31e1d19c 100644 --- a/src/x86/ffiw64.c +++ b/src/x86/ffiw64.c @@ -190,7 +190,7 @@ ffi_prep_closure_loc (ffi_closure* closure, /* nopl (%rax) */ 0x0f, 0x1f, 0x00 }; - unsigned char *tramp = closure->tramp; + char *tramp = closure->tramp; if (cif->abi != FFI_WIN64) return FFI_BAD_ABI; From 1f6b5a91f417ac77d2fe9b0b3eb66293db132e2e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 26 Jul 2015 16:27:34 -0700 Subject: [PATCH 4/4] Support the WIN64/EFI64 calling convention on all X86_64 platforms Add a new calling convention FFI_EFI64, alias FFI_WIN64, on all X86_64 platforms. This allows libffi compiled on a 64-bit x86 platform to call EFI functions. Compile in ffiw64.c and win64.S on all X86_64 platforms. When compiled for a platform other than X86_WIN64, ffiw64.c suffixes its functions with _efi64, to avoid conflict with the platform's actual implementations of those functions. --- configure.host | 2 +- src/x86/ffi64.c | 32 ++++++++++++++++++++++++++++++++ src/x86/ffitarget.h | 2 ++ src/x86/ffiw64.c | 16 +++++++++------- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/configure.host b/configure.host index c6f6a02e..a4a22b78 100644 --- a/configure.host +++ b/configure.host @@ -246,7 +246,7 @@ case "${TARGET}" in SOURCES="ffi.c sysv.S" ;; X86_64) - SOURCES="ffi64.c unix64.S" + SOURCES="ffi64.c unix64.S ffiw64.c win64.S" ;; X86_WIN64) SOURCES="ffiw64.c win64.S" diff --git a/src/x86/ffi64.c b/src/x86/ffi64.c index 131b5e3d..f52749e9 100644 --- a/src/x86/ffi64.c +++ b/src/x86/ffi64.c @@ -388,6 +388,9 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], /* Perform machine dependent cif processing. */ +extern ffi_status +ffi_prep_cif_machdep_efi64(ffi_cif *cif); + ffi_status ffi_prep_cif_machdep (ffi_cif *cif) { @@ -396,6 +399,8 @@ ffi_prep_cif_machdep (ffi_cif *cif) size_t bytes, n, rtype_size; ffi_type *rtype; + if (cif->abi == FFI_EFI64) + return ffi_prep_cif_machdep_efi64(cif); if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; @@ -657,22 +662,41 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, flags, rvalue, fn); } +extern void +ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); + void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { + if (cif->abi == FFI_EFI64) + return ffi_call_efi64(cif, fn, rvalue, avalue); ffi_call_int (cif, fn, rvalue, avalue, NULL); } +extern void +ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure); + void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { + if (cif->abi == FFI_EFI64) + ffi_call_go_efi64(cif, fn, rvalue, avalue, closure); ffi_call_int (cif, fn, rvalue, avalue, closure); } + extern void ffi_closure_unix64(void) FFI_HIDDEN; extern void ffi_closure_unix64_sse(void) FFI_HIDDEN; +extern ffi_status +ffi_prep_closure_loc_efi64(ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc); + ffi_status ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif, @@ -691,6 +715,8 @@ ffi_prep_closure_loc (ffi_closure* closure, void (*dest)(void); char *tramp = closure->tramp; + if (cif->abi == FFI_EFI64) + return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc); if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; @@ -805,10 +831,16 @@ ffi_closure_unix64_inner(ffi_cif *cif, extern void ffi_go_closure_unix64(void) FFI_HIDDEN; extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN; +extern ffi_status +ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)); + ffi_status ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*)) { + if (cif->abi == FFI_EFI64) + return ffi_prep_go_closure_efi64(closure, cif, fun); if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; diff --git a/src/x86/ffitarget.h b/src/x86/ffitarget.h index 8c1dcac2..25e3f4f5 100644 --- a/src/x86/ffitarget.h +++ b/src/x86/ffitarget.h @@ -87,6 +87,8 @@ typedef enum ffi_abi { #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, + FFI_WIN64, + FFI_EFI64 = FFI_WIN64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 diff --git a/src/x86/ffiw64.c b/src/x86/ffiw64.c index 31e1d19c..0029be02 100644 --- a/src/x86/ffiw64.c +++ b/src/x86/ffiw64.c @@ -30,6 +30,10 @@ #include #ifdef X86_WIN64 +#define EFI64(name) name +#else +#define EFI64(name) name##_efi64 +#endif struct win64_call_frame { @@ -44,7 +48,7 @@ extern void ffi_call_win64 (void *stack, struct win64_call_frame *, void *closure) FFI_HIDDEN; ffi_status -ffi_prep_cif_machdep (ffi_cif *cif) +EFI64(ffi_prep_cif_machdep)(ffi_cif *cif) { int flags, n; @@ -159,13 +163,13 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, } void -ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +EFI64(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, +EFI64(ffi_call_go)(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure) { ffi_call_int (cif, fn, rvalue, avalue, closure); @@ -176,7 +180,7 @@ extern void ffi_closure_win64(void) FFI_HIDDEN; extern void ffi_go_closure_win64(void) FFI_HIDDEN; ffi_status -ffi_prep_closure_loc (ffi_closure* closure, +EFI64(ffi_prep_closure_loc)(ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, @@ -206,7 +210,7 @@ ffi_prep_closure_loc (ffi_closure* closure, } ffi_status -ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, +EFI64(ffi_prep_go_closure)(ffi_go_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*)) { if (cif->abi != FFI_WIN64) @@ -277,5 +281,3 @@ ffi_closure_win64_inner(ffi_cif *cif, fun (cif, rvalue, avalue, user_data); return flags; } - -#endif /* X86_WIN64 */