2007-12-30 17:41:49 +01:00
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
gbx_extern.c
|
|
|
|
|
|
|
|
Extern calls in dynamic libraries
|
|
|
|
|
|
|
|
(c) 2000-2007 Benoit Minisini <gambas@users.sourceforge.net>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 1, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __GBX_EXTERN_C
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "gb_common.h"
|
2008-01-17 22:39:26 +01:00
|
|
|
|
2008-05-10 17:17:07 +02:00
|
|
|
#if HAVE_FFI_COMPONENT
|
2008-01-17 22:39:26 +01:00
|
|
|
#include <ffi.h>
|
2008-05-10 17:17:07 +02:00
|
|
|
#endif
|
2008-01-17 22:39:26 +01:00
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
#include "gb_common_buffer.h"
|
|
|
|
#include "gb_table.h"
|
|
|
|
#include "gbx_type.h"
|
|
|
|
#include "gbx_value.h"
|
|
|
|
#include "gbx_class.h"
|
|
|
|
#include "gbx_exec.h"
|
|
|
|
#include "gbx_api.h"
|
|
|
|
|
|
|
|
#include "gbx_extern.h"
|
|
|
|
|
|
|
|
typedef
|
|
|
|
struct {
|
|
|
|
SYMBOL sym;
|
|
|
|
lt_dlhandle handle;
|
|
|
|
}
|
|
|
|
EXTERN_SYMBOL;
|
|
|
|
|
|
|
|
static TABLE *_table = NULL;
|
|
|
|
|
2008-05-10 17:17:07 +02:00
|
|
|
#if HAVE_FFI_COMPONENT
|
2008-01-17 22:39:26 +01:00
|
|
|
static ffi_type *_to_ffi_type[17] = {
|
|
|
|
&ffi_type_void, &ffi_type_sint32, &ffi_type_sint32, &ffi_type_sint32,
|
|
|
|
&ffi_type_sint32, &ffi_type_sint64, &ffi_type_float, &ffi_type_double,
|
|
|
|
&ffi_type_void, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_void,
|
|
|
|
&ffi_type_void, &ffi_type_void, &ffi_type_void, &ffi_type_pointer,
|
|
|
|
&ffi_type_pointer
|
|
|
|
};
|
2008-05-10 17:17:07 +02:00
|
|
|
#endif
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
static lt_dlhandle get_library(char *name)
|
|
|
|
{
|
|
|
|
EXTERN_SYMBOL *esym;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (!_table)
|
|
|
|
TABLE_create(&_table, sizeof(EXTERN_SYMBOL), TF_NORMAL);
|
|
|
|
|
|
|
|
TABLE_add_symbol(_table, name, strlen(name), (SYMBOL **)(void *)&esym, NULL);
|
|
|
|
if (!esym->handle)
|
|
|
|
{
|
|
|
|
/* !!! Must add the suffix !!! */
|
|
|
|
|
|
|
|
p = strrchr(name, ':');
|
|
|
|
if (!p)
|
2008-01-17 22:39:26 +01:00
|
|
|
sprintf(COMMON_buffer, "%s." SHARED_LIBRARY_EXT, name);
|
2007-12-30 17:41:49 +01:00
|
|
|
else
|
2008-01-17 22:39:26 +01:00
|
|
|
sprintf(COMMON_buffer, "%.*s." SHARED_LIBRARY_EXT ".%s", (int)(p - name), name, p + 1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
name = COMMON_buffer;
|
|
|
|
|
|
|
|
#ifndef DONT_USE_LTDL
|
2008-01-03 21:44:46 +01:00
|
|
|
/* no more available in libltld ?
|
2007-12-30 17:41:49 +01:00
|
|
|
lt_dlopen_flag = RTLD_LAZY;
|
2008-01-03 21:44:46 +01:00
|
|
|
*/
|
2007-12-30 17:41:49 +01:00
|
|
|
esym->handle = lt_dlopenext(name);
|
|
|
|
#else
|
|
|
|
esym->handle = dlopen(name, RTLD_LAZY);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (esym->handle == NULL)
|
|
|
|
THROW(E_EXTLIB, name, lt_dlerror());
|
|
|
|
|
|
|
|
//fprintf(stderr, "%s loaded.\n", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return esym->handle;
|
|
|
|
}
|
|
|
|
|
2008-05-10 17:17:07 +02:00
|
|
|
#if 0
|
|
|
|
static int put_arg(void *addr, VALUE *value)
|
|
|
|
{
|
|
|
|
static void *jump[16] = {
|
|
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
|
|
&&__STRING, &&__STRING, &&__VARIANT, &&__ARRAY, &&__FUNCTION, &&__CLASS, &&__NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
if (TYPE_is_object(value->type))
|
|
|
|
goto __OBJECT;
|
|
|
|
else
|
|
|
|
goto *jump[value->type];
|
|
|
|
|
|
|
|
__BOOLEAN:
|
|
|
|
|
|
|
|
*((int *)addr) = (value->_boolean.value != 0 ? 1 : 0);
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__BYTE:
|
|
|
|
|
|
|
|
*((int *)addr) = (unsigned char)(value->_byte.value);
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__SHORT:
|
|
|
|
|
|
|
|
*((int *)addr) = (short)(value->_short.value);
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__INTEGER:
|
|
|
|
|
|
|
|
*((int *)addr) = value->_integer.value;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__LONG:
|
|
|
|
|
|
|
|
*((int64_t *)addr) = value->_long.value;
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
__SINGLE:
|
|
|
|
|
|
|
|
*((float *)addr) = (float)value->_float.value;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__FLOAT:
|
|
|
|
|
|
|
|
*((double *)addr) = value->_float.value;
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
__DATE:
|
|
|
|
|
|
|
|
/* Inverser au cas o value ~= addr */
|
|
|
|
|
|
|
|
((int *)addr)[1] = value->_date.time;
|
|
|
|
((int *)addr)[0] = value->_date.date;
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
__STRING:
|
|
|
|
|
|
|
|
*((char **)addr) = (char *)(value->_string.addr + value->_string.start);
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__OBJECT:
|
|
|
|
|
|
|
|
{
|
|
|
|
void *ob = value->_object.object;
|
|
|
|
CLASS *class = OBJECT_class(ob);
|
|
|
|
|
|
|
|
if (!CLASS_is_native(class) && class == CLASS_Class)
|
|
|
|
*((void **)addr) = class->stat;
|
|
|
|
else
|
|
|
|
*((void **)addr) = (char *)ob + sizeof(OBJECT);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__NULL:
|
|
|
|
*((void **)addr) = NULL;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
__VARIANT:
|
|
|
|
__VOID:
|
|
|
|
__ARRAY:
|
|
|
|
__CLASS:
|
|
|
|
__FUNCTION:
|
|
|
|
|
|
|
|
ERROR_panic("Bad type (%d) for EXTERN_call", value->type);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
static void *get_function(CLASS_EXTERN *ext)
|
|
|
|
{
|
|
|
|
lt_dlhandle handle;
|
|
|
|
void *func;
|
|
|
|
|
|
|
|
if (ext->loaded)
|
|
|
|
return (void *)ext->alias;
|
|
|
|
|
|
|
|
handle = get_library(ext->library);
|
|
|
|
func = lt_dlsym(handle, ext->alias);
|
|
|
|
|
|
|
|
if (func == NULL)
|
|
|
|
{
|
|
|
|
lt_dlclose(handle);
|
|
|
|
THROW(E_EXTSYM, ext->library, ext->alias);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ext->library = (char *)handle;
|
|
|
|
ext->alias = (char *)func;
|
|
|
|
ext->loaded = TRUE;
|
|
|
|
|
|
|
|
return func;
|
|
|
|
}
|
2008-01-17 22:39:26 +01:00
|
|
|
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
/*
|
|
|
|
EXEC.class : the class
|
|
|
|
EXEC.index : the extern function index
|
|
|
|
EXEC.nparam : the number of parameters to the call
|
|
|
|
EXEC.drop : if the return value should be dropped.
|
|
|
|
*/
|
|
|
|
|
2008-05-10 17:17:07 +02:00
|
|
|
#if HAVE_FFI_COMPONENT
|
2008-01-17 22:39:26 +01:00
|
|
|
void EXTERN_call(void)
|
|
|
|
{
|
|
|
|
static const void *jump[17] = {
|
|
|
|
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
|
|
|
&&__STRING, &&__STRING, &&__VARIANT, &&__ARRAY, &&__FUNCTION, &&__CLASS, &&__NULL, &&__OBJECT
|
|
|
|
};
|
|
|
|
static const int use_temp[17] = { 0, 0, 0, 0, 0, 0, sizeof(float), 0, 0, sizeof(char *), sizeof(char *), 0, 0, 0, 0, 0, sizeof(void *) };
|
|
|
|
static char temp[4 * sizeof(void *)];
|
|
|
|
static void *null = 0;
|
|
|
|
|
|
|
|
CLASS_EXTERN *ext = &EXEC.class->load->ext[EXEC.index];
|
|
|
|
int nparam = EXEC.nparam;
|
|
|
|
ffi_cif cif;
|
|
|
|
ffi_type *types[nparam];
|
|
|
|
ffi_type *rtype;
|
|
|
|
void *args[nparam];
|
|
|
|
TYPE *sign;
|
|
|
|
VALUE *value;
|
|
|
|
char *tmp = NULL;
|
|
|
|
char *next_tmp;
|
|
|
|
void *func;
|
|
|
|
int i, t;
|
2008-08-14 21:42:27 +02:00
|
|
|
union {
|
|
|
|
int _integer;
|
|
|
|
float _single;
|
|
|
|
double _float;
|
|
|
|
char * _string;
|
|
|
|
int64_t _long;
|
|
|
|
}
|
|
|
|
rvalue;
|
2008-01-17 22:39:26 +01:00
|
|
|
|
|
|
|
if (nparam < ext->n_param)
|
|
|
|
THROW(E_NEPARAM);
|
|
|
|
if (nparam > ext->n_param)
|
|
|
|
THROW(E_TMPARAM);
|
|
|
|
|
|
|
|
sign = (TYPE *)ext->param;
|
|
|
|
value = &SP[-nparam];
|
|
|
|
next_tmp = temp;
|
|
|
|
|
|
|
|
for (i = 0; i < nparam; i++, value++, sign++)
|
|
|
|
{
|
|
|
|
VALUE_conv(value, *sign);
|
|
|
|
|
|
|
|
if (TYPE_is_object(value->type))
|
|
|
|
t = T_OBJECT;
|
|
|
|
else
|
|
|
|
t = (int)value->type;
|
|
|
|
|
|
|
|
if (use_temp[t])
|
|
|
|
{
|
|
|
|
tmp = next_tmp;
|
|
|
|
if ((tmp + use_temp[t]) > &temp[sizeof(temp)])
|
|
|
|
THROW(E_TMPARAM);
|
|
|
|
args[i] = tmp;
|
|
|
|
next_tmp = tmp + use_temp[t];
|
|
|
|
}
|
|
|
|
types[i] = _to_ffi_type[t];
|
|
|
|
goto *jump[t];
|
|
|
|
|
|
|
|
__BOOLEAN:
|
|
|
|
__BYTE:
|
|
|
|
__SHORT:
|
|
|
|
__INTEGER:
|
|
|
|
args[i] = &value->_integer.value;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__LONG:
|
|
|
|
args[i] = &value->_long.value;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__SINGLE:
|
|
|
|
*((float *)tmp) = (float)value->_float.value;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__FLOAT:
|
|
|
|
args[i] = &value->_float.value;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__STRING:
|
|
|
|
*((char **)tmp) = (char *)(value->_string.addr + value->_string.start);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__OBJECT:
|
|
|
|
{
|
|
|
|
void *ob = value->_object.object;
|
|
|
|
CLASS *class = OBJECT_class(ob);
|
|
|
|
|
|
|
|
if (!CLASS_is_native(class) && class == CLASS_Class)
|
|
|
|
*((void **)tmp) = class->stat;
|
|
|
|
else
|
|
|
|
*((void **)tmp) = (char *)ob + sizeof(OBJECT);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__NULL:
|
|
|
|
args[i] = &null;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__DATE:
|
|
|
|
__VARIANT:
|
|
|
|
__VOID:
|
|
|
|
__ARRAY:
|
|
|
|
__CLASS:
|
|
|
|
__FUNCTION:
|
|
|
|
|
|
|
|
ERROR_panic("Bad type (%d) for EXTERN_call", value->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
rtype = _to_ffi_type[ext->type];
|
|
|
|
|
|
|
|
func = get_function(ext);
|
|
|
|
|
|
|
|
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nparam, rtype, types) != FFI_OK)
|
|
|
|
ERROR_panic("ffi_prep_cif has failed");
|
|
|
|
|
2008-08-14 21:42:27 +02:00
|
|
|
ffi_call(&cif, func, &rvalue, args);
|
2008-01-17 22:39:26 +01:00
|
|
|
|
|
|
|
switch (ext->type)
|
|
|
|
{
|
|
|
|
case T_BOOLEAN:
|
|
|
|
case T_BYTE:
|
|
|
|
case T_SHORT:
|
|
|
|
case T_INTEGER:
|
2008-08-14 21:42:27 +02:00
|
|
|
//GB_ReturnInteger(*(int *)POINTER(rvalue));
|
|
|
|
GB_ReturnInteger(rvalue._integer);
|
2008-01-17 22:39:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_LONG:
|
2008-08-14 21:42:27 +02:00
|
|
|
//GB_ReturnLong(*(int64_t *)POINTER(rvalue));
|
|
|
|
GB_ReturnLong(rvalue._long);
|
2008-01-17 22:39:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_SINGLE:
|
2008-08-14 21:42:27 +02:00
|
|
|
//GB_ReturnFloat(*(float *)POINTER(rvalue));
|
|
|
|
GB_ReturnFloat(rvalue._single);
|
2008-01-17 22:39:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_FLOAT:
|
2008-08-14 21:42:27 +02:00
|
|
|
//GB_ReturnFloat(*(double *)POINTER(rvalue));
|
|
|
|
GB_ReturnFloat(rvalue._float);
|
2008-01-17 22:39:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_STRING:
|
2008-08-14 21:42:27 +02:00
|
|
|
//GB_ReturnConstString(*(char **)POINTER(rvalue), 0);
|
|
|
|
GB_ReturnConstString(rvalue._string, 0);
|
2008-01-17 22:39:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
//GB_ReturnNull();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (nparam > 0)
|
|
|
|
{
|
|
|
|
nparam--;
|
|
|
|
POP();
|
|
|
|
}
|
|
|
|
|
|
|
|
POP(); /* extern function */
|
|
|
|
|
|
|
|
/* from EXEC_native() */
|
|
|
|
|
|
|
|
BORROW(&TEMP);
|
|
|
|
|
|
|
|
if (EXEC.drop)
|
|
|
|
RELEASE(&TEMP);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VALUE_conv(&TEMP, ext->type);
|
|
|
|
*SP = TEMP;
|
|
|
|
SP++;
|
|
|
|
}
|
|
|
|
}
|
2008-05-10 17:17:07 +02:00
|
|
|
#else
|
|
|
|
void EXTERN_call(void)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2008-05-10 17:17:07 +02:00
|
|
|
THROW(E_ILLEGAL);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
2008-01-17 22:39:26 +01:00
|
|
|
#endif
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-01-17 22:39:26 +01:00
|
|
|
void EXTERN_exit(void)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
EXTERN_SYMBOL *esym;
|
|
|
|
|
|
|
|
if (!_table)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < TABLE_count(_table); i++)
|
|
|
|
{
|
|
|
|
esym = (EXTERN_SYMBOL *)TABLE_get_symbol(_table, i);
|
|
|
|
if (esym->handle)
|
|
|
|
lt_dlclose(esym->handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
TABLE_delete(&_table);
|
|
|
|
}
|