mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Support calling convention specific function name mangling
On Windows certain calling conventions cause C function names to be mangled, so to import them we have to use the properly mangled names.
This commit is contained in:
parent
f12dc90e5e
commit
1ed9ebdea5
3 changed files with 81 additions and 2 deletions
|
@ -765,6 +765,38 @@ again:
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
#if defined(ZEND_WIN32) && (defined(HAVE_FFI_FASTCALL) || defined(HAVE_FFI_STDCALL))
|
||||
static size_t zend_ffi_arg_size(zend_ffi_type *type) /* {{{ */
|
||||
{
|
||||
zend_ffi_type *arg_type;
|
||||
size_t arg_size = 0;
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
|
||||
arg_size += ZEND_FFI_TYPE(arg_type)->size;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
return arg_size;
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
||||
static zend_always_inline zend_string *zend_ffi_mangled_func_name(zend_string *name, zend_ffi_type *type) /* {{{ */
|
||||
{
|
||||
#ifdef ZEND_WIN32
|
||||
switch (type->func.abi) {
|
||||
# ifdef HAVE_FFI_FASTCALL
|
||||
case FFI_FASTCALL:
|
||||
return strpprintf(0, "@%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
|
||||
# endif
|
||||
# ifdef HAVE_FFI_STDCALL
|
||||
case FFI_STDCALL:
|
||||
return strpprintf(0, "_%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
return zend_string_copy(name);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#if FFI_CLOSURES
|
||||
typedef struct _zend_ffi_callback_data {
|
||||
zend_fcall_info_cache fcc;
|
||||
|
@ -2842,7 +2874,10 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
|
|||
}
|
||||
sym->addr = addr;
|
||||
} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
|
||||
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
|
||||
zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
|
||||
|
||||
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
|
||||
zend_string_release(mangled_name);
|
||||
if (!addr) {
|
||||
zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
|
||||
}
|
||||
|
@ -3172,7 +3207,10 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
|||
}
|
||||
sym->addr = addr;
|
||||
} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
|
||||
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
|
||||
zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
|
||||
|
||||
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
|
||||
zend_string_release(mangled_name);
|
||||
if (!addr) {
|
||||
if (preload) {
|
||||
zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
|
||||
|
|
41
ext/ffi/tests/callconv.phpt
Normal file
41
ext/ffi/tests/callconv.phpt
Normal file
|
@ -0,0 +1,41 @@
|
|||
--TEST--
|
||||
Different calling conventions
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
if (substr(PHP_OS, 0, 3) != 'WIN') die('skip for Windows only');
|
||||
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platforms only");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$header = <<<HEADER
|
||||
void __cdecl cdecl_func(int arg1, double arg2);
|
||||
void __stdcall stdcall_func(int arg1, double arg2);
|
||||
void __fastcall fastcall_func(int arg1, double arg2);
|
||||
HEADER;
|
||||
$headername = __DIR__ . '/callconv.h';
|
||||
$dllname = __DIR__ . "/callconv_x86.dll";
|
||||
|
||||
$ffi1 = FFI::cdef($header, $dllname);
|
||||
$ffi1->cdecl_func(1, 2.3);
|
||||
$ffi1->stdcall_func(4, 5.6);
|
||||
$ffi1->fastcall_func(7, 8.9);
|
||||
|
||||
file_put_contents($headername, "#define FFI_LIB \"$dllname\"\n$header");
|
||||
|
||||
$ffi2 = FFI::load($headername);
|
||||
$ffi2->cdecl_func(2, 3.4);
|
||||
$ffi2->stdcall_func(5, 6.7);
|
||||
$ffi2->fastcall_func(8, 9.1);
|
||||
?>
|
||||
--EXPECT--
|
||||
cdecl: 1, 2.300000
|
||||
stdcall: 4, 5.600000
|
||||
fastcall: 7, 8.900000
|
||||
cdecl: 2, 3.400000
|
||||
stdcall: 5, 6.700000
|
||||
fastcall: 8, 9.100000
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/callconv.h');
|
||||
?>
|
BIN
ext/ffi/tests/callconv_x86.dll
Normal file
BIN
ext/ffi/tests/callconv_x86.dll
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue