From: alhy@courant.SLAC.Stanford.EDU (J. Scott Berg)
Subject: Re: problem load()-ing shared object
Reply-To: ALHY@slac.stanford.edu
Organization: Stanford University, dept of Physics / SLAC
Date: Tue, 29 Dec 1992 04:50:46 GMT

In article <609@bertha.HyperDesk.com>, adennie@ibm3.hyperdesk.com (Andy Dennie) writes:
|> I've been playing around with shared objects on AIX 3.2, and although I
|> can successfully load and execute a simple function in a shared object,
|> I'm stumped on the following problem: how do you load a shared object
|> that contains references to globals defined in the program doing the
|> loading?  Below is a simple test case that illustrates the problem.
|> 
|> Any help would be greatly appreciated!
|> 
|> foo2.c contains:
|> ----------------------------------------------------------------------
|> #include <errno.h>
|> #include <stdio.h>
|> #include <sys/ldr.h>
|> 
|> char global_string[] = "hello, world\n";  /* here's the global */
|> 
|> main() {
|>     int (*pfunc)() = load("bar.so", 0, (char*)NULL);
|> 
|>     if (pfunc == 0) {
|>         printf("load failed, errno=%d\n", errno);
|>     }
|> }
|> ----------------------------------------------------------------------
|> 
|> 
|> bar2.c contains:
|> ----------------------------------------------------------------------
|> extern char *global_string;
|> 
|> void bar () {
|>     printf("%s", global_string);
|> }
|> ----------------------------------------------------------------------
|> 
|> bar2.exp contains:
|> ------------------
|> bar
|> ------------------
|> 
|> bar2.imp contains:
|> ------------------
|> global_string
|> ------------------
|> 
|> % make foo2 bar2.so
|>         xlc -o foo2 -D_ALL_SOURCE -D_ANSI_C_SOURCE -D_POSIX_SOURCE foo2.c
|>         xlc -o bar2.so -bM:SRE -bE:bar2.exp -bI:bar2.imp -e _nostart bar2.c
|> % foo2
|> load failed, errno=8
|> 
|> 
|> BTW, $LIBPATH contains the current directory, where bar2.so resides.  I
|> think I'm probably doing something wrong with bar2.imp.  I've tried
|> adding
|> 
|> #!/pathname/of/foo
|> 
|> to the beginning of it, but that didn't help.  I also tried creating a
|> foo2.exp file and linking foo2 with the -bE:foo2.exp switch (same
|> results).  Any ideas? 

I hacked around on this for a while, and here's what I could figure out:

To get it to load, you need to put something in the import file telling it
what to do about finding the external references.

If you put 

#!

as the first line, it treats it as a "delayed resolve", which as far
as I can tell is not resolved by the load() function call.  You need
to call loadbind() to resolve it.  But you need another load()'ed
program to do the resolve with.  It seems (it's hard to tell) that you
can give loadbind a symbol name within your code and it will try to do
the resolve.  You need to tell foo2 to export the global_string (I
think).  When you do this, the load call works fine, it resolves the
symbol to something, but that something happens to be garbage.  Beats
me why.  If you instead put

#!./foo2

in your bar2.inp, the same thing happens (you don't even have to do
the loadbind() call).  If you use the #! alone, but don't do the
loadbind call, it segment faults even trying to figure out the value
of the pointer global_string.  It ALWAYS segment faults when you try
to reference the pointer (i.e., print the string).

Anyhow, I'm sure this isn't making much sense to you, because it
certainly doesn't make any sense to me.  Enclosed is my current
version of your test code which basically has more diagnostics and
gets past the load part.

Good luck!  If you figure out how to do this, I'd love to know.  God
bless

					-Scott Berg

When executed, my foo2 outputs:

Err: 0
10000000 5761 20041800 104
foo2
d07ea000 1749 20047400 24
bar2.so
Test: hello, world

20041810
Got here!
68656c6c           <---- Wouldn't have printed this without the loadbind()
Segmentation fault



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

foo2.c:

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

#include <errno.h>
#include <stdio.h>
#include <sys/ldr.h>

char global_string[] = "hello, world\n";  /* here's the global */

main() {

  char *buffer[1024];
  char *yo;

    int (*pfunc)() = load("bar2.so", 0, (char*)NULL);

  printf("Err: %d\n",loadbind(0,global_string,pfunc));

  loadquery(L_GETINFO,buffer,sizeof buffer);
  yo = (char *) buffer;
  while (((struct ld_info *)yo)->ldinfo_next != 0) {
    printf("%p %u %p %u\n",((struct ld_info *)yo)->ldinfo_textorg,
	   ((struct ld_info *)yo)->ldinfo_textsize,
	   ((struct ld_info *)yo)->ldinfo_dataorg,
	   ((struct ld_info *)yo)->ldinfo_datasize);
    printf(((struct ld_info *)yo)->ldinfo_filename);
    printf("\n");
    yo += ((struct ld_info *)yo)->ldinfo_next;
  }
  

  printf("Test: %s\n",global_string);
  printf("%p\n",global_string);
  
    if (pfunc == 0) {
        printf("load failed, errno=%d\n", errno);
	perror("Yo!");
	buffer[0] = "execerror";
	buffer[1] = "foo2";
	loadquery(L_GETMESSAGES, &buffer[2], sizeof buffer -8);
	execvp("/etc/execerror",buffer);
    }

  pfunc();
}

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

foo2.exp:

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

global_string

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

bar2.c:

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

extern char *global_string;

void bar () {
  printf("Got here!\n");
  printf("%p\n",global_string);
    printf("%s", global_string);
}

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

bar2.inp

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

#!
global_string

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

bar2.exp

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

bar

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

Makefile

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

foo2 :  foo2.c foo2.exp
	xlc -bE:foo2.exp -L. -o foo2 -D_ALL_SOURCE -D_ANSI_C_SOURCE -D_POSIX_SOURCE foo2.c

bar2.so : bar2.c bar2.inp bar2.exp
	xlc -L. -o bar2.so -bM:SRE -bE:bar2.exp -bI:bar2.inp -e _nostart bar2.c

-- 
-------------------------------------------------------------------------------
The opinions expressed here are, of course, my own and nobody else's.
-------------------------------------------------------------------------------
J. Scott Berg
email: ALHY@slac.stanford.edu
real mail: Varian Physics
           Stanford  CA  94305-4060
phone:	(415) 926-4732 (w)
 	(415) 326-2631 (h)
-------------------------------------------------------------------------------