From 1f6b5a91f417ac77d2fe9b0b3eb66293db132e2e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 26 Jul 2015 16:27:34 -0700 Subject: [PATCH] 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 c6f6a02..a4a22b7 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 131b5e3..f52749e 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 8c1dcac..25e3f4f 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 31e1d19..0029be0 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 */ -- 2.7.4