Newbie questions about Pliant

Newbie questions about Pliant

Loading shared libraries

Same code works with C, but not with Pliant.

Message posted by reitman on 2003/10/15 07:24:46
Hi,

I am having problem using a dynamic library from Pliant.  Here are two equivalent
.c and .pli files, that call function demodynaload() in the library 
libdemodynaload.c (file demodynaload_lib.c).   In one case it works, 
in the other one it doesn't.  

The sample run,

  IN C:  (correct output) 

    $ make
    gcc -shared -o libdemodynaload.so demodynaload_lib.c xsinit.c `/usr/bin/perl -MExtUtils::Embed -e ccopts -e ldopts`
    gcc -o demodynaload demodynaload.c -L. -ldemodynaload 

    $ ./demodynaload 
    SV = IV(0x8060b1c) at 0x804a51c
      REFCNT = 1
      FLAGS = (PADBUSY,PADMY,IOK,pIOK)
      IV = 1


  IN PLIANT:  (doesn't work)

    $ pliant demodynaload.pli 

    Can't load '/usr/lib/perl/5.8.1/auto/Devel/Peek/Peek.so' for module Devel::Peek: /usr/lib/perl/5.8.1/auto/Devel/Peek/Peek.so: undefined symbol: Perl_runops_debug at /usr/lib/perl/5.8.1/XSLoader.pm line 68.
     at /usr/lib/perl/5.8.1/Devel/Peek.pm line 19
    Compilation failed in require at (eval 1) line 1.
    BEGIN failed--compilation aborted at (eval 1) line 1.
    
If I do "nm -D Perl_runops_debug" on libdemodynalod.pli, it is indeed missing.

The code,

  ::::::::::::::
  demodynaload.c
  ::::::::::::::

    extern void demodynaload();

    int main()
    {
      demodynaload();  # invoke
    }

  ::::::::::::::
  demodynaload.pli
  ::::::::::::::

    function demodynaload 
      external "libdemodynaload.so" "demodynaload"

    demodynaload      # invoke


  ::::::::::::::
  demodynaload_lib.c
  ::::::::::::::

    #include <EXTERN.h>
    #include <perl.h>
    #include <stdio.h>


    PerlInterpreter *my_perl;

    EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);

    EXTERN_C void
    xs_init(pTHX)
    {
            char *file = __FILE__;
            dXSUB_SYS;

            /* DynaLoader is a special case */
            newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
    }

    int demodynaload()
    {
      char *embedding[] = { "", "-e", "0" };
      my_perl = perl_alloc();
      perl_construct(my_perl);

      perl_parse(my_perl, xs_init, 3, embedding, NULL);
      perl_eval_pv("use Devel::Peek; my $a = 1; Dump($a);", 1);

      perl_destruct(my_perl);
      perl_free(my_perl);
    }
Message posted by hubert.tonneau on 2003/10/15 09:25:48
What is xsinit.c ?

Also I bet Perl does some dirty things, because I've already seen some perl
script that work when called from bash, but not when called from a Pliant
'execute' command, which is in facts Linux 'execve' kernel instruction.
Message posted by reitman on 2003/10/15 17:04:31
Sorry,  I forgot to show the new Makefile line, after I moved the contents
of xsinit.c into demodynaload_lib.c, and got rid of xsinit.c completely.

The file contents are the same as before. Here are the new make line, 
and a sample run with the same output.

$ make
gcc -shared -o libdemodynaload.so demodynaload_lib.c `/usr/bin/perl -MExtUtils::Embed -e ccopts -e ldopts`
gcc -o demodynaload demodynaload.c -L. -ldemodynaload 

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`

$ ./demodynaload 
SV = IV(0x806099c) at 0x804a51c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1

$ pliant demodynaload.pli 
Can't load '/usr/lib/perl/5.8.1/auto/Devel/Peek/Peek.so' for module Devel::Peek: /usr/lib/perl/5.8.1/auto/Devel/Peek/Peek.so: undefined symbol: Perl_runops_debug at /usr/lib/perl/5.8.1/XSLoader.pm line 68.
 at /usr/lib/perl/5.8.1/Devel/Peek.pm line 19
Compilation failed in require at (eval 1) line 1.
BEGIN failed--compilation aborted at (eval 1) line 1.
Message posted by reitman on 2003/10/15 21:54:18
An update,

I have spoken to a friend of mine, about this problem and he said
that I need to load the library with RTLD_GLOBAL
as in

  dlopen(lib, RTLD_GLOBAL)

I will investigate this, and will get back with my results.
Message posted by reitman on 2003/10/16 08:09:57
Alright, the problem is ineed in the flag given to dlopen. The following 
diff to language/os/dll.c fixes the problem,
(this is against pliant version 86).

======================================================
--- dll.c       Thu Feb 15 05:37:15 2001
+++ /pliant/pliant/language/os/dll.c    Thu Oct 16 01:08:19 2003
@@ -25,6 +25,9 @@

   void * _EXTERNAL_ dlopen(const char *filename,int flag);
   #define RTLD_LAZY 1
+  #define RTLD_NOW        0x00002
+  #define RTLD_GLOBAL     0x00100
   void * _EXTERNAL_ dlsym(void *,const char *);
   int _EXTERNAL_ dlclose(void *);
   #if defined(_SO1_) && !defined(_DLL_)
@@ -36,7 +39,7 @@
     struct Str namez;
     void *handle; void *fn;
     Str_build(&namez); Str_concat(&namez,S,dllname,EOS);
-    handle=dlopen(namez.chars,RTLD_LAZY);
+    handle=dlopen(namez.chars,RTLD_NOW|RTLD_GLOBAL);
     Str_destroy(&namez);
     if(handle==null) {
   #if defined(_OpenBSD_)  /* don't lie */

==============================================================

This brings up the following questions. Can this diff be applied ? 
In other words is it always ok to use RTLD_GLOBAL|RTLD_NOW instead of 
RTLD_LAZY... It seems that RTLD_LAZY is more efficient. So, it this is the case,
perhaps the 'external' pliant function attribute can be modified to 
accept some flags.  Or perhaps there should be a pliant directive like,

dlopen "liblibrary.so" myflag

where you explicitely force a dlopen so that the dlopen inside dll.c will 
not do anything (I understand that this is what happens when you call dlopen 
twice on the same file).

What are you suggestions ? 
Boris
Message posted by hubert.tonneau on 2003/10/16 10:38:43
The change will be in release 87.