Here's one of the patches I promised. This provides native AIX dynamic
library support in libltdl. The AIX loader code was stolen from Jens
Uwe-Mager's dlfcn.shar library, http://www.han.de/~jum/aix/dlfcn.shar
and slightly massaged to fit into the libltdl framework. (For anyone
who cares, Perl 5's dynaloader also appears to use an older version
of Jens' code for its AIX support. Unfortunately, that version doesn't
work on AIX 4. I've been meaning to submit a patch to fix this but
haven't yet. So if you're having problems with dynamically loaded perl
modules on AIX 4, that's why.)

There are also a couple small bugfixes to the win32 support - don't call
strchr on NULL filenames, and treat a NULL handle as a reference to the
main program.

I will try to generate a patch against the HEAD branch next.

Howard Chu - Black GTS   http://highlandsun.com
http://people.we.mediaone.net/hyc
Index: ltdl.c
===================================================================
RCS file: /home/cvs/libtool/libltdl/ltdl.c,v
retrieving revision 1.64.2.19
diff -u -r1.64.2.19 ltdl.c
--- ltdl.c      2000/09/04 01:53:05     1.64.2.19
+++ ltdl.c      2000/10/13 13:39:37
@@ -206,7 +206,7 @@
 
 #endif
 
-#if HAVE_LIBDL
+#if defined(HAVE_LIBDL) && !defined(_AIX)
 
 /* dynamic linking with dlopen/dlsym */
 
@@ -458,6 +458,7 @@
        if (dld_link(filename) != 0) {
                last_error = cannot_open_error;
                lt_dlfree(handle->handle);
+               handle->handle = NULL;
                return 1;
        }
        return 0;
@@ -472,6 +473,8 @@
                return 1;
        }
        lt_dlfree(handle->filename);
+       handle->handle = NULL;
+       handle->filename = NULL;
        return 0;
 }
 
@@ -497,6 +500,431 @@
 
 #endif
 
+#ifdef _AIX
+
+/* dynamic linking for AIX */
+
+#include <sys/types.h>
+#include <sys/reg.h>
+#include <execargs.h>
+#include <errno.h>
+#include <sys/ldr.h>
+#include <a.out.h>
+#include <ldfcn.h>
+
+/*
+ * AIX 4.3 removes some useful definitions from ldfcn.h. Define
+ * these here to compensate for that lossage.
+ */
+#ifndef BEGINNING
+# define BEGINNING SEEK_SET
+#endif
+#ifndef FSEEK
+# define FSEEK(ldptr,o,p)      fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) 
++o):o,p)
+#endif
+#ifndef FREAD
+# define FREAD(p,s,n,ldptr)    fread(p,s,n,IOPTR(ldptr))
+#endif
+
+/*
+ * We simulate dlopen() et al. through a call to load. Because AIX has
+ * no call to find an exported symbol we read the loader section of the
+ * loaded module and build a list of exported symbols and their virtual
+ * address.
+ */
+
+typedef struct {
+       char            *name;          /* the symbols's name */
+       lt_ptr_t        *addr;          /* its relocated virtual address */
+} Export, *ExportPtr;
+
+/*
+ * The void * handle returned from dlopen is actually a ModulePtr.
+ */
+typedef struct Module {
+       void            *entry;         /* entry point from load */
+       int             nExports;       /* the number of exports found */
+       ExportPtr       exports;        /* the array of exports */
+} Module, *ModulePtr;
+
+static void *mainModule;
+static char errbuf[BUFSIZ];
+
+static int readExports(ModulePtr);
+
+static void caterr(char *s)
+{
+       register char *p = s;
+
+       while (isdigit(*p)) p++;
+
+       last_error = errbuf;
+
+       switch(atoi(s)) {
+       case L_ERROR_TOOMANY:
+               last_error = "too many errors";
+               break;
+       case L_ERROR_NOLIB:
+               strcpy(errbuf, "can't load library");
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_UNDEF:
+               strcpy(errbuf, symbol_error);
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_RLDBAD:
+               strcpy(errbuf, "bad RLD");
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_FORMAT:
+               strcpy(errbuf, "bad exec format in");
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_ERRNO:
+               last_error = strerror(atoi(++p));
+               break;
+       case L_ERROR_MEMBER:
+               strcpy(errbuf, "member not found");
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_TYPE:
+               strcpy(errbuf, "symbol type mismatch");
+               strcat(errbuf, p);
+               break;
+       case L_ERROR_ALIGN:
+               last_error = "bad text alignment";
+               break;
+       case L_ERROR_DOMCREAT:
+               last_error = "cannot create loader domain";
+               break;
+       case L_ERROR_DOMADD:
+               last_error = "cannot add to loader domain";
+               break;
+       case L_ERROR_SYSTEM:
+               strcpy(errbuf, "system error");
+               strcat(errbuf, p);
+               break;
+       default:
+               strcpy(errbuf, s);
+               break;
+       }
+}
+
+/*
+ * Find the main module's entry point. This is used as export pointer
+ * for loadbind() to be able to resolve references to the main part.
+ */
+static int
+sys_aix_init LTDL_PARAMS((void))
+{
+       struct ld_info *lp;
+       char *buf;
+       int size = 4*1024;
+       int i;
+       void *ret;
+
+       if ((buf = lt_dlmalloc(size)) == NULL) {
+               last_error = memory_error;
+               return -1;
+       }
+       while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
+               lt_dlfree(buf);
+               size += 4*1024;
+               if ((buf = lt_dlmalloc(size)) == NULL) {
+                       last_error = memory_error;
+                       return -1;
+               }
+       }
+       if (i == -1) {
+               last_error = strerror(errno);
+               lt_dlfree(buf);
+               return -1;
+       }
+       /*
+        * The first entry is the main module. The entry point
+        * returned by load() actually points to the data
+        * segment origin.
+        */
+       lp = (struct ld_info *)buf;
+       mainModule = lp->ldinfo_dataorg;
+       lt_dlfree(buf);
+       return 0;
+}
+
+static int
+sys_aix_exit LTDL_PARAMS((void))
+{
+       return 0;
+}
+
+/* Forward declaration... */
+static lt_dlhandle handles;
+
+static int sys_aix_doclose(ModulePtr mp);
+
+static int
+sys_aix_open (handle, filename)
+       lt_dlhandle handle;
+       const char *filename;
+{
+       register ModulePtr mp = lt_dlmalloc(sizeof(Module));
+       lt_dlhandle cur;
+
+       handle->handle = NULL;
+       if (!mp) {
+               last_error = memory_error;
+               return 1;
+       }
+       mp->nExports = 0;
+       mp->exports = NULL;
+       if (!filename) {
+               mp->entry = mainModule;
+       } else {
+           if (!(mp->entry = (lt_ptr_t)load((char *)filename, 0, NULL))) {
+               char *tmp[BUFSIZ/sizeof(char *)];
+               lt_dlfree(mp);
+               if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
+                       last_error = strerror(errno);
+               else
+                       caterr(tmp[0]);
+
+               return 1;
+           }
+           if (loadbind(0, mainModule, mp->entry) == -1) {
+                sys_aix_doclose(mp);
+                last_error = strerror(errno);
+                return 1;
+           }
+           for (cur=handles; cur; cur=cur->next) {
+               ModulePtr m2 = (ModulePtr)cur->handle;
+               if (m2 && loadbind(0, m2->entry, mp->entry) == -1) {
+                       sys_aix_doclose(mp);
+                       last_error = strerror(errno);
+                       return 1;
+               }
+           }
+       }
+       if (readExports(mp) == -1) {
+               sys_aix_doclose(mp);
+               return 1;
+       }
+       handle->handle = mp;
+       return 0;
+}
+
+static int sys_aix_doclose(ModulePtr mp)
+{
+       int result;
+
+       result = unload(mp->entry);
+       if (result == -1) {
+               last_error = strerror(errno);
+       }
+       if (mp->exports) {
+               register ExportPtr ep;
+               register int i;
+               for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
+                       if (ep->name)
+                               lt_dlfree(ep->name);
+               lt_dlfree(mp->exports);
+       }
+       lt_dlfree(mp);
+       return result;
+}
+
+static int
+sys_aix_close(handle)
+       lt_dlhandle handle;
+{
+       register ModulePtr mp = (ModulePtr)handle->handle;
+       int res = sys_aix_doclose(mp);
+       handle->handle = NULL;
+       return res;
+}
+
+static lt_ptr_t
+sys_aix_sym (handle, symbol)
+       lt_dlhandle handle;
+       const char *symbol;
+{
+       register ModulePtr mp = (ModulePtr)handle->handle;
+       register ExportPtr ep;
+       register int i;
+
+       /*
+        * Could speed up search, but I assume that one assigns
+        * the result to function pointers anyways.
+        */
+       for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
+               if (strcmp(ep->name, symbol) == 0)
+                       return ep->addr;
+       last_error = symbol_error;
+       return NULL;
+}
+/*
+ * Build the export table from the XCOFF .loader section.
+ */
+static int
+readExports(mp)
+       ModulePtr mp;
+{
+       LDFILE *ldp = NULL;
+       SCNHDR sh, shdata;
+       LDHDR *lhp;
+       char *ldbuf;
+       LDSYM *ls;
+       int i;
+       ExportPtr ep;
+       struct ld_info *lp;
+       char *buf;
+       int size = 4*1024;
+       void *dataorg;
+
+       if (mp->entry == mainModule) {
+               char ***args = (char ***)ARGS_loc;
+               dataorg = mainModule;
+               ldp = ldopen(*args[0], ldp);
+       } else {
+
+       /*
+        * The module might be loaded due to the LIBPATH
+        * environment variable. Search for the loaded
+        * module using L_GETINFO.
+        */
+       if ((buf = lt_dlmalloc(size)) == NULL) {
+               last_error = memory_error;
+               return -1;
+       }
+       while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
+               lt_dlfree(buf);
+               size += 4*1024;
+               if ((buf = lt_dlmalloc(size)) == NULL) {
+                       last_error = memory_error;
+                       return -1;
+               }
+       }
+       if (i == -1) {
+               last_error = strerror(errno);
+               lt_dlfree(buf);
+               return -1;
+       }
+       /*
+        * Traverse the list of loaded modules. The entry point
+        * returned by load() does actually point to the data
+        * segment origin.
+        */
+       lp = (struct ld_info *)buf;
+       while (lp) {
+               if ((unsigned long)mp->entry >= (unsigned long)lp->ldinfo_dataorg &&
+                   (unsigned long)mp->entry < (unsigned long)lp->ldinfo_dataorg +
+                     lp->ldinfo_datasize) {
+                       dataorg = lp->ldinfo_dataorg;
+                       ldp = ldopen(lp->ldinfo_filename, ldp);
+                       break;
+               }
+               if (lp->ldinfo_next == 0)
+                       lp = NULL;
+               else
+                       lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
+       }
+       lt_dlfree(buf);
+       }
+       if (!ldp) {
+               last_error = strerror(errno);
+               return -1;
+       }
+       if (TYPE(ldp) != U802TOCMAGIC) {
+               last_error = "bad magic";
+               while(ldclose(ldp) == FAILURE)
+                       ;
+               return -1;
+       }
+       if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
+               last_error = "cannot read data section header";
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
+               last_error = "cannot read loader section header";
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       /*
+        * We read the complete loader section in one chunk, this makes
+        * finding long symbol names residing in the string table easier.
+        */
+       if ((ldbuf = (char *)lt_dlmalloc(sh.s_size)) == NULL) {
+               last_error = memory_error;
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
+               last_error = "cannot seek to loader section";
+               lt_dlfree(ldbuf);
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
+               last_error = "cannot read loader section";
+               lt_dlfree(ldbuf);
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       lhp = (LDHDR *)ldbuf;
+       ls = (LDSYM *)(ldbuf+LDHDRSZ);
+       /*
+        * Count the number of exports to include in our export table.
+        */
+       for (i = lhp->l_nsyms; i; i--, ls++) {
+               if (!LDR_EXPORT(*ls))
+                       continue;
+               mp->nExports++;
+       }
+       mp->exports = lt_dlmalloc(sizeof(Export)*mp->nExports);
+       if (mp->exports == NULL) {
+               last_error = memory_error;
+               lt_dlfree(ldbuf);
+               while(ldclose(ldp) == FAILURE) ;
+               return -1;
+       }
+       /*
+        * Fill in the export table. All entries are relative to
+        * the beginning of the data section.
+        */
+       ep = mp->exports;
+       ls = (LDSYM *)(ldbuf+LDHDRSZ);
+       for (i = lhp->l_nsyms; i; i--, ls++) {
+               char *symname;
+               char tmpsym[SYMNMLEN+1];
+               if (!LDR_EXPORT(*ls))
+                       continue;
+               if (ls->l_zeroes == 0)
+                       symname = ls->l_offset+lhp->l_stoff+ldbuf;
+               else {
+                       strncpy(tmpsym, ls->l_name, SYMNMLEN);
+                       tmpsym[SYMNMLEN] = '\0';
+                       symname = tmpsym;
+               }
+               ep->name = strdup(symname);
+               ep->addr = (void *)((unsigned long)dataorg + ls->l_value -
+                                       shdata.s_vaddr);
+               ep++;
+       }
+       lt_dlfree(ldbuf);
+       while(ldclose(ldp) == FAILURE) ;
+       return 0;
+       }
+
+static
+lt_dltype_t
+sys_aix = { LTDL_TYPE_TOP, 0, sys_aix_init, sys_aix_exit,
+       sys_aix_open, sys_aix_close, sys_aix_sym };
+
+#undef LTDL_TYPE_TOP
+#define LTDL_TYPE_TOP &sys_aix
+
+#endif /* _AIX */
+
 #ifdef _WIN32
 
 /* dynamic linking for Win32 */
@@ -524,23 +952,32 @@
        const char *filename;
 {
        lt_dlhandle cur;
-       char *searchname = NULL;
-       char *ext = strrchr(filename, '.');
 
-       if (ext) {
-               /* FILENAME already has an extension. */
-               searchname = strdup(filename);
-       } else {
-               /* Append a `.' to stop Windows from adding an
-                  implicit `.dll' extension. */
-               searchname = (char*)lt_dlmalloc(2+ strlen(filename));
-               strcpy(searchname, filename);
-               strcat(searchname, ".");
-       }
-    
-       handle->handle = LoadLibrary(searchname);
-       lt_dlfree(searchname);
-       
+       if (filename)
+       {
+               char *searchname = NULL;
+               char *ext = strrchr(filename, '.');
+
+               if (ext) {
+                       /* FILENAME already has an extension. */
+                       searchname = strdup(filename);
+               } else {
+                       /* Append a `.' to stop Windows from adding an
+                          implicit `.dll' extension. */
+                       searchname = (char*)lt_dlmalloc(2+ strlen(filename));
+                       strcpy(searchname, filename);
+                       strcat(searchname, ".");
+               }
+
+               handle->handle = LoadLibrary(searchname);
+               lt_dlfree(searchname);
+       }
+       else
+       {
+               handle->handle = GetModuleHandle(NULL);
+               return 0;
+       }
+
        /* libltdl expects this function to fail if it is unable
           to physically load the library.  Sadly, LoadLibrary
           will search the loaded libraries for a match and return
@@ -549,6 +986,7 @@
           We check whether LoadLibrary is returning a handle to
           an already loaded module, and simulate failure if we
           find one. */
+
        cur = handles;
        while (cur) {
                if (!cur->handle) {
@@ -586,6 +1024,20 @@
 {
        lt_ptr_t address = GetProcAddress(handle->handle, symbol);
        
+       if (!address && !handle->filename)
+       {
+               lt_dlhandle cur;
+
+               for (cur = handles; cur; cur=cur->next)
+               {
+                       if (cur == handle)
+                               continue;
+                       address = GetProcAddress(cur->handle, symbol);
+                       if (address)
+                               break;
+               }
+       }
+
        if (!address)
                last_error = symbol_error;
        return address;
@@ -932,6 +1384,13 @@
        
        cur = *handle;
        if (filename) {
+               FILE *f = fopen(filename, "r");
+               if (!f)
+               {
+                       last_error = file_not_found_error;
+                       return 1;
+               }
+               fclose(f);
                cur->filename = strdup(filename);
                if (!cur->filename) {
                        last_error = memory_error;
@@ -946,7 +1405,10 @@
        }
        if (!type) {
                if (cur->filename)
+               {
                        lt_dlfree(cur->filename);
+                       cur->filename = NULL;
+               }
                return 1;
        }
        cur->type = type;
@@ -971,6 +1433,7 @@
        if (old_name && tryall_dlopen(handle, old_name) == 0)
                return 0;
        /* try to open the dynamic library */
+       last_error = NULL;
        if (dlname) {
                /* try to open the installed module */
                if (installed && libdir) {
@@ -987,6 +1450,8 @@
                        lt_dlfree(filename);
                        if (error)
                                return 0;
+                       if (last_error != file_not_found_error)
+                               return 1;
                }
                /* try to open the not-installed module */
                if (!installed) {
@@ -1008,6 +1473,8 @@
                        lt_dlfree(filename);
                        if (error)
                                return 0;
+                       if (last_error != file_not_found_error)
+                               return 1;
                }
                /* hmm, maybe it was moved to another directory */
                {
@@ -1025,7 +1492,8 @@
                                return 0;
                }
        }
-       last_error = file_not_found_error;
+       if (!last_error)
+               last_error = file_not_found_error;
        return 1;
 }
 

Reply via email to