Re: FFI experimentation, some advice please...

Daniel Diaz <[email protected]>
Newsgroups gmane.comp.gnu.prolog.general
Message-ID <[email protected]>
Hi,

I understand the problem you state but it is due to the fact that
you want to provide all libld functionalities at the Prolog level.
I'm not sure it is a good idea. Allowing the user to load
arbitrarily an dynamic lib and invoke any function provided by the
lib can be very dangerous: we are handling pointers as simple
Prolog integers. Btw a C pointer cannot be safely casted to a
Prolog integer which use some bits (currently 3) for the tag (e.g.
on a 32 bits machine, gprolog integers are on 29 bits).

I'm however convinced that it is important to provide Prolog
built-in predicates to load a Prolog module dynamically (I don't
mean "consult" but load a natively compiled Prolog module). Such
built-ins would rely on dlopen,dlsym (or equivalent functions
under windows) internally but they would not be directly
accessible by the user (except if he use the C interface
obviously). To be loadable a Prolog source file should be compiled
by gplc in a specific way to provide a dynamic lib (.so ou .dll
under windows). I'm working on this with the introduction of a
module system for gprolog.

Daniel

Le 05/07/2013 00:56, Sean Charles a écrit :

Without pasting *all* my code, I have wrapped dlopen/dlclose/dlsym
and dlerror and then added this to my C code base:

typedef int (*FUNCPTR)(int,int);

PlBool

ffi_call2(PlLong fn, PlLong n1,
PlLong n2, PlLong* result)

{

FUNCPTR callee = (FUNCPTR)fn;

*result = (*callee)( (int)n1,
(int)n2 );

return PL_TRUE;

}

and in my interface test file I have this:

:- foreign( dlopen( +codes,
-positive ), [ fct_name( gp_dlopen )]).

:- foreign( dlclose( +positive ),
[ fct_name( gp_dlclose )]).

:- foreign( dlclose_strict(
+positive ), [ fct_name( gp_dlclose_strict )]).

:- foreign( dlerror( -string ),
[ fct_name( gp_dlerror )]).

:- foreign( dlsym( +positive,
+codes, -positive ), [ fct_name( gp_dlsym )]).

%% This is to test the "add2"
function to establish the protocol...

:- foreign( ffi_call2( +positive,
+positive, +positive, -positive )).

and finally, some actual prolog test code and the output…

test1(N1,N2,Result) :-

( dlopen("libtest.so", H)

->

dlsym(H, "add2", F),

test2(F,N1,N2,Result),

dlclose(H)

;

dlerror(M),

format("ERROR: ~a~n",
[M])

).

%% Proves I can pass "F" around
and it still work mightily...

test2(F,N1,N2,Result) :-

ffi_call2(F, N1, N2, Result).

and finally the output:

| ?- test1(100,333,X).

dlsym: handle:7fd1b2c19b10,
symbol: add2 ==> 109349f50

X = 433

yes

Hurrah, it works. The extra output is a printf() in the C
code just to show what's going on.

That's all fine and well but as it is right now I would have
to create lots of "FUNCPTR" variations to cope with all the
possible signature types… obviously unworkable as this is
intended to be a dynamic system. The question then is what is
the most effective way to allow call-site code to arbitrarily
load a library, grab a function and then call it with prolog
terms as arguments?

I can use FIOArg* as the input, I can use a list of them to
cope with multiple functions and assume the last one is a return
value. IFF there is a return value. Now you see the enormity of
the task, how to generalise a call to any function that takes
any number of differing types of arguments and may or may not
return something on the stack or be "void".

I think the the ultimate answer is some filthy dirt raw
assembler code that pushes stuff onto the stack and then does
the call and tidies up the stack frame etc. I don't mind doing
that but I was hoping that seeing as how "foreign" already
exists and gplc does such an amazing job that there might be
code "inside the box" that I can re-use for this. I would dearly
love to create a generic FFI for GNU Prolog that we could then
use to wrap and call any externally available C library.

Of course, the calling code will know the context of what it
is trying to do and can supply the necessary information which
led me to some dreamt up vapour code that might look like this:

ffi_call( "lib test.so", int(
add2( int(100), int(333))), Result).

ffi_callV( "lib test.so",
add2( int(100), int(333)))). %% callV => VOID, no return
value

Inside my C code I could then pick apart the functor and its
arguments and do the right thing…somehow. I smell assembler! I
don't mind. I cut my teeth on it 28 years ago and still program
PIC micros for people so I am not afraid of that or the dark!

I am already having delusions of grandeur and thinking about
using RabbitMQ, Redis and MySQL and writing non-deterministic
code that returns each row of a result set or keeps reading from
an AMQP queue just because I can. For my day job, the ability to
showcase Prolog would be great but it has to connect to all the
usual stuff to be seen to be useful.

Ha. Welcome to the world of FFI! OK, 11:56 PM in the UK
again, time for tubby bye byes.

:)

Cheers,

Sean.

--

Ce message a été vérifié par
MailScanner
pour des virus ou des polluriels et rien de
suspect n'a été trouvé.

_______________________________________________
Users-prolog mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/users-prolog

--

Ce message a été vérifié par
MailScanner
pour des virus ou des polluriels et rien de
suspect n'a été trouvé.

_______________________________________________
Users-prolog mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/users-prolog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.