[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 01/12] Support loading shared library archive members.
From: |
Michael Haubenwallner |
Subject: |
[PATCH 01/12] Support loading shared library archive members. |
Date: |
Tue, 2 Oct 2012 17:34:42 +0200 |
AIX supports shared objects as members of archive libraries, loadable
with dlopen using the RTLD_MEMBER flag.
* libltdl/ltdl.c: For AIX, define LT_SHARED_LIB_MEMBER to hold the
parentheses used to identify the shared archive member.
(lt_dlopenadvise) When LT_SHARED_LIB_MEMBER is defined, allow for
specifying an archive member as the to-be-loaded shared object.
* libltdl/loaders/dlopen.c: (vm_open) Use RTLD_MEMBER flag for dlopen
when the filename does specify an archive member between "()".
---
libltdl/loaders/dlopen.c | 18 ++++
libltdl/ltdl.c | 202 ++++++++++++++++++++++++++++++++++++----------
2 files changed, 178 insertions(+), 42 deletions(-)
diff --git a/libltdl/loaders/dlopen.c b/libltdl/loaders/dlopen.c
index e8180e1..a71f5e0 100644
--- a/libltdl/loaders/dlopen.c
+++ b/libltdl/loaders/dlopen.c
@@ -168,6 +168,9 @@ vm_open (lt_user_data LT__UNUSED loader_data, const char
*filename,
{
int module_flags = LT_LAZY_OR_NOW;
lt_module module;
+#ifdef RTLD_MEMBER
+ int len = LT_STRLEN (filename);
+#endif
if (advise)
{
@@ -191,6 +194,21 @@ vm_open (lt_user_data LT__UNUSED loader_data, const char
*filename,
#endif
}
+#ifdef RTLD_MEMBER /* AIX */
+ if (len)
+ {
+ /* Advise loading an archive member only if the filename
+ really contains both the opening and closing parent. */
+ const char *closing = strrchr(filename ? filename : "", ')');
+ if (closing && STREQ(closing, ")"))
+ {
+ const char *opening = strrchr(filename, '(');
+ if (opening && strchr(opening, '/') == NULL)
+ module_flags |= RTLD_MEMBER;
+ }
+ }
+#endif
+
module = dlopen (filename, module_flags);
if (!module)
diff --git a/libltdl/ltdl.c b/libltdl/ltdl.c
index 0dea0c8..c958d79 100644
--- a/libltdl/ltdl.c
+++ b/libltdl/ltdl.c
@@ -58,6 +58,12 @@ or obtained by writing to the Free Software Foundation, Inc.,
# define LT_LIBPREFIX "lib"
#endif
+/* how shared archive members are specified, seen on AIX only */
+#undef LT_SHARED_LIB_MEMBER
+#if defined _AIX
+# define LT_SHARED_LIB_MEMBER "()" /* need the parentheses only */
+#endif
+
/* This is the maximum symbol size that won't require malloc/free */
#undef LT_SYMBOL_LENGTH
#define LT_SYMBOL_LENGTH 128
@@ -77,6 +83,9 @@ static const char objdir[] =
LT_OBJDIR;
static const char archive_ext[] = LT_ARCHIVE_EXT;
static const char libext[] = LT_LIBEXT;
static const char libprefix[] = LT_LIBPREFIX;
+#if defined LT_SHARED_LIB_MEMBER
+static const char shared_lib_member[] = LT_SHARED_LIB_MEMBER;
+#endif
#if defined LT_MODULE_EXT
static const char shlib_ext[] = LT_MODULE_EXT;
#endif
@@ -127,7 +136,6 @@ static int find_module (lt_dlhandle
*handle, const char *dir,
const char *libdir, const char *dlname,
const char *old_name, int installed,
lt_dladvise advise);
-static int has_library_ext (const char *filename);
static int load_deplibs (lt_dlhandle handle, char *deplibs);
static int trim (char **dest, const char *str);
static int try_dlopen (lt_dlhandle *handle,
@@ -582,6 +590,97 @@ find_module (lt_dlhandle *handle, const char *dir, const
char *libdir,
return 1;
}
+/* Identify extension and optional shared archive member of a library FILENAME.
+ Sets *PMEMBER to the member specification found, or end of FILENAME.
+ Sets *PEXT to the extension found, or to *PMEMBER - may be end of FILENAME.
+ When FILENAME is NULL, *PEXT and *PMEMBER are set to NULL.
+ With ANY_EXT, FILENAME must not containy any path, and '.' is used to
+ search for the extension. */
+static void
+identify_library_ext_member(const char *filename,
+ const char **pext, const char **pmember, int any_ext)
+{
+ size_t len;
+ size_t extlen;
+
+ assert (pext);
+ assert (pmember);
+
+ len = LT_STRLEN (filename); /* enough to work with filename == NULL */
+
+ *pmember = filename + len; /* member specification is identified later */
+
+ extlen = LT_STRLEN(archive_ext);
+ if (len > extlen && STREQ (filename + len - extlen, archive_ext))
+ {
+ /* with libtool archive, member specification is unsupported */
+ *pext = filename + len - extlen;
+ return;
+ }
+
+#if defined LT_SHARED_LIB_MEMBER
+ /* Take first and last char of shared_lib_member as the parentheses,
+ and ensure there is something in between the parentheses. */
+ extlen = LT_STRLEN(shared_lib_member);
+ if (len > 3 && extlen >= 2
+ && filename[len-1] == shared_lib_member[extlen-1]) /* closing */
+ {
+ const char *member;
+ member = strrchr(filename, shared_lib_member[0]); /* opening */
+ if (member && member <= filename + len - 3) /* something in between */
+ {
+ *pmember = member;
+ len = member - filename; /* Ignore member for the extension search. */
+ }
+ }
+#endif
+
+#if defined LT_MODULE_EXT
+ extlen = LT_STRLEN(shlib_ext);
+ if (len > extlen && strncmp(filename + len - extlen, shlib_ext, extlen) == 0)
+ {
+ *pext = filename + len - extlen;
+ return;
+ }
+#endif
+#if defined LT_SHARED_EXT
+ extlen = LT_STRLEN(shared_ext);
+ if (len > extlen && strncmp(filename + len - extlen, shared_ext, extlen) ==
0)
+ {
+ *pext = filename + len - extlen;
+ return;
+ }
+#endif
+
+#if defined LT_SHARED_LIB_MEMBER
+ /* AIX allows for shared objects in libNAME.a archive too */
+ extlen = LT_STRLEN(libext); /* libext lacks leading '.' */
+ if (len > (extlen + 1)
+ && filename[len - extlen - 1] == '.'
+ && strncmp(filename + len - extlen, libext, extlen) == 0)
+ {
+ *pext = filename + len - extlen - 1;
+ return;
+ }
+#endif
+
+ /* maybe an archive member, but no extension found so far */
+ *pext = *pmember;
+
+ if (len > 1 && any_ext) {
+ /* search for last '.' before member, */
+ const char *ext = filename;
+ while((ext = strchr(ext, '.')) != NULL)
+ {
+ if (ext >= *pmember) /* found '.' in the member name */
+ break;
+ *pext = ext;
+ ++ext;
+ }
+ }
+
+ return;
+}
static int
canonicalize_path (const char *path, char **pcanonical)
@@ -782,9 +881,27 @@ static int
find_handle_callback (char *filename, void *data, void *data2)
{
lt_dlhandle *phandle = (lt_dlhandle *) data;
- int notfound = access (filename, R_OK);
+ int notfound;
lt_dladvise advise = (lt_dladvise) data2;
+#if defined LT_SHARED_LIB_MEMBER
+ const char *ext;
+ const char *member;
+ identify_library_ext_member(filename, &ext, &member, 0);
+ /* Omit the shared archive member name, which is something like
+ "(shr.o)" on AIX, when checking if the file is access-ible.
+ But there must be some filename before the member. */
+ if (*member && member > filename)
+ {
+ /* cut off member for filesystem check */
+ filename[member - filename] = LT_EOS_CHAR;
+ notfound = access (filename, R_OK);
+ /* restore member for dlopen */
+ filename[member - filename] = shared_lib_member[0];
+ }
+ else
+#endif
+ notfound = access (filename, R_OK);
/* Bail out if file cannot be read... */
if (notfound)
return 0;
@@ -1168,6 +1285,7 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
char * attempt = 0;
int errors = 0;
lt_dlhandle newhandle;
+ const char * member;
assert (phandle);
assert (*phandle == 0);
@@ -1205,11 +1323,22 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
if (ext)
{
- attempt = MALLOC (char, LT_STRLEN (filename) + LT_STRLEN (ext) + 1);
+ const char *tmpext;
+ int filenamelen, extlen;
+
+ /* Use ext and/or member when specified as argument. */
+
+ identify_library_ext_member(filename, &tmpext, &member, 0);
+
+ filenamelen = tmpext - filename;
+ extlen = ext ? strlen (ext) : (member - tmpext);
+
+ attempt = MALLOC (char, filenamelen + extlen + strlen (member) + 1);
if (!attempt)
return 1;
- sprintf(attempt, "%s%s", filename, ext);
+ sprintf(attempt, "%.*s%.*s%s", filenamelen, filename,
+ extlen, ext ? ext : tmpext, member);
}
else
{
@@ -1250,14 +1379,10 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
assert (base_name && *base_name);
- ext = strrchr (base_name, '.');
- if (!ext)
- {
- ext = base_name + LT_STRLEN (base_name);
- }
+ identify_library_ext_member(base_name, &ext, &member, 1); /* any extension */
/* extract the module name from the file name */
- name = MALLOC (char, ext - base_name + 1);
+ name = MALLOC (char, ext - base_name + strlen (member) + 1);
if (!name)
{
++errors;
@@ -1266,7 +1391,7 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
/* canonicalize the module name */
{
- int i;
+ int i, j;
for (i = 0; i < ext - base_name; ++i)
{
if (isalnum ((unsigned char)(base_name[i])))
@@ -1278,7 +1403,20 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
name[i] = '_';
}
}
- name[ext - base_name] = LT_EOS_CHAR;
+ /* Need member name for unique identification of shared objects.
+ NOTE: dlpreopen is static only, without a shared member. */
+ for (j = 0; member[j] != LT_EOS_CHAR; ++j, ++i)
+ {
+ if (isalnum ((unsigned char)(member[j])))
+ {
+ name[i] = member[j];
+ }
+ else
+ {
+ name[i] = '_';
+ }
+ }
+ name[i] = LT_EOS_CHAR;
}
/* Before trawling through the file system in search of a module,
@@ -1330,8 +1468,10 @@ try_dlopen (lt_dlhandle *phandle, const char *filename,
const char *ext,
goto cleanup;
}
- /* Check whether we are opening a libtool module (.la extension). */
- if (ext && STREQ (ext, archive_ext))
+ /* Check whether we are opening a libtool module (.la extension).
+ An archive member is not allowed this way: STREQ filters that,
+ as the member immediately follows the extension in base_name. */
+ if (STREQ (ext, archive_ext))
{
/* this seems to be a libtool module */
FILE * file = 0;
@@ -1534,33 +1674,6 @@ file_not_found (void)
}
-/* Unless FILENAME already bears a suitable library extension, then
- return 0. */
-static int
-has_library_ext (const char *filename)
-{
- const char * ext = 0;
-
- assert (filename);
-
- ext = strrchr (filename, '.');
-
- if (ext && ((STREQ (ext, archive_ext))
-#if defined LT_MODULE_EXT
- || (STREQ (ext, shlib_ext))
-#endif
-#if defined LT_SHARED_EXT
- || (STREQ (ext, shared_ext))
-#endif
- ))
- {
- return 1;
- }
-
- return 0;
-}
-
-
/* Initialise and configure a user lt_dladvise opaque object. */
int
@@ -1651,6 +1764,8 @@ lt_dlopenadvise (const char *filename, lt_dladvise advise)
lt_dlhandle handle = 0;
int errors = 0;
const char * saved_error = 0;
+ const char * ext;
+ const char * member;
LT__GETERROR (saved_error);
@@ -1661,10 +1776,13 @@ lt_dlopenadvise (const char *filename, lt_dladvise
advise)
return 0;
}
+ identify_library_ext_member(filename, &ext, &member, 0);
+
if (!filename
|| !advise
|| !advise->try_ext
- || has_library_ext (filename))
+ || member > ext /* filename has a known extension */
+ )
{
/* Just incase we missed a code path in try_dlopen() that reports
an error, but forgot to reset handle... */
--
1.7.3.4
- [PATCH 00/12] Improve AIX support: libltdl, filename-based versioning., Michael Haubenwallner, 2012/10/02
- [PATCH 01/12] Support loading shared library archive members.,
Michael Haubenwallner <=
- [PATCH 04/12] Specify shared member in soname_spec on AIX., Michael Haubenwallner, 2012/10/02
- [PATCH 11/12] No cross-library undefined symbols test on AIX., Michael Haubenwallner, 2012/10/02
- [PATCH 06/12] Drop useless symlinks with AIX runtime linking., Michael Haubenwallner, 2012/10/02
- [PATCH 08/12] Implement enable/disable aix-soname options., Michael Haubenwallner, 2012/10/02
- [PATCH 05/12] AIX runtime linking allows undef syms by default., Michael Haubenwallner, 2012/10/02
- [PATCH 03/12] Do not remove shared archive member in mode clean., Michael Haubenwallner, 2012/10/02
- [PATCH 07/12] Declare enable/disable aix-soname options., Michael Haubenwallner, 2012/10/02
- [PATCH 10/12] Detect XFAIL based on hardcode configuration., Michael Haubenwallner, 2012/10/02
- [PATCH 02/12] Prepare -dlopen option for shared archive members., Michael Haubenwallner, 2012/10/02
- [PATCH 12/12] Set aix-soname=yes as default., Michael Haubenwallner, 2012/10/02