Subject: Mozilla / dlopen
To: None <port-i386@netbsd.org, tech-toolchain@netbsd.org>
From: Frank van der Linden <frank@wins.uva.nl>
List: tech-toolchain
Date: 12/08/1998 01:10:51
Quoting myself:
> I don't know why the global dlopen() fails, that looks like a bug. It
> happens for me too when running mozilla-current on i386-current with egcs,
> and I haven't looked into it any further.
[note follow-up to tech-toolchain]
I looked into this further, and noticed the following problem scenario,
which happens on a.out systems:
1) Create a C++ shared library with global constructors
2) In such a constructor, place a call to dlopen
3) Link a program with it, and start it
4) a.out crt0 gets called. it calls the dynamic linker. ld_entry (entry
points for dl*() calls) are not yet set up.
5) The dynamic linker starts doing its job. It finds the C++ shared lib,
and calls the .init section in it, which wakes care of the global
constructors (if c++rt0 was linked in, anyway)
6) The global constructor calls dlopen(), which is in crt0
7) ld_entry has not yet been initialized, do dlopen() fails.
8) ld_entry will later be initialized, but this is too late.
So, anytime dlopen() is called in some way from a global constructor
in a shared library, it will fail, since it doesn't know it's actual
stub dl*() entry points yet.
I worked around this by giving ld_entry an extra indirection, setting
it before the runtime linker is called, and modified the runtime linker
to fill in the ld_entry field before it starts resolving libraries.
This appears to work, but it's just a quick hack, and I haven't even
checked if the rtld code is up to this task, i.e. if messing around
with dl*() in global constructors in a more serious way then
mozilla does will create havoc in its data structures (it probably will).
Workaround included below. I assume we may not want to spend too much
effort in cleaning dl*() up for a.out platforms, so it might do until
we switch to ELF in the future. Comments (esp. from people who know
the rtld code a little better)?
- Frank
P.S. About the original problem: mozilla crashes further along now,
but that is a different problem.
*** lib/csu/common.c.orig Tue Oct 20 21:14:00 1998
--- lib/csu/common.c Tue Dec 8 00:36:25 1998
***************
*** 39,45 ****
#ifdef DYNAMIC
typedef int (*rtld_entry_fn) __P((int, struct crt_ldso *));
! static struct ld_entry *ld_entry;
static void
__load_rtld(dp)
--- 39,45 ----
#ifdef DYNAMIC
typedef int (*rtld_entry_fn) __P((int, struct crt_ldso *));
! static struct ld_entry **ld_entry;
static void
__load_rtld(dp)
***************
*** 134,139 ****
--- 134,140 ----
/* Call Sun's ld.so entry point: version 1, offset crt */
__call(CRT_VERSION_SUN, &crt, crt.crt_ba + sizeof hdr);
#else
+ ld_entry = &crt.crt_ldentry;
entry = (rtld_entry_fn)(crt.crt_ba + sizeof hdr);
if ((*entry)(CRT_VERSION_BSD_4, &crt) == -1) {
/* Feeble attempt to deal with out-dated ld.so */
***************
*** 143,153 ****
if ((*entry)(CRT_VERSION_BSD_3, &crt) == -1) {
_FATAL("ld.so failed\n");
}
! ld_entry = dp->d_entry;
return;
}
! ld_entry = crt.crt_ldentry;
! atexit(ld_entry->dlexit);
#endif
#if defined(sun) && defined(DUPZFD)
--- 144,153 ----
if ((*entry)(CRT_VERSION_BSD_3, &crt) == -1) {
_FATAL("ld.so failed\n");
}
! ld_entry = &dp->d_entry;
return;
}
! atexit((*ld_entry)->dlexit);
#endif
#if defined(sun) && defined(DUPZFD)
***************
*** 168,187 ****
const char *name;
int mode;
{
! if (ld_entry == NULL)
return NULL;
! return (ld_entry->dlopen)(name, mode);
}
int
dlclose(fd)
void *fd;
{
! if (ld_entry == NULL)
return -1;
! return (ld_entry->dlclose)(fd);
}
void *
--- 168,187 ----
const char *name;
int mode;
{
! if ((*ld_entry) == NULL)
return NULL;
! return ((*ld_entry)->dlopen)(name, mode);
}
int
dlclose(fd)
void *fd;
{
! if ((*ld_entry) == NULL)
return -1;
! return ((*ld_entry)->dlclose)(fd);
}
void *
***************
*** 189,198 ****
void *fd;
const char *name;
{
! if (ld_entry == NULL)
return NULL;
! return (ld_entry->dlsym)(fd, name);
}
int
--- 189,198 ----
void *fd;
const char *name;
{
! if ((*ld_entry) == NULL)
return NULL;
! return ((*ld_entry)->dlsym)(fd, name);
}
int
***************
*** 200,209 ****
void *fd, *arg;
int cmd;
{
! if (ld_entry == NULL)
return -1;
! return (ld_entry->dlctl)(fd, cmd, arg);
}
char *
--- 200,209 ----
void *fd, *arg;
int cmd;
{
! if ((*ld_entry) == NULL)
return -1;
! return ((*ld_entry)->dlctl)(fd, cmd, arg);
}
char *
***************
*** 211,218 ****
{
int error;
! if (ld_entry == NULL ||
! (*ld_entry->dlctl)(NULL, DL_GETERRNO, &error) == -1)
return "Service unavailable";
return ((char *)(error == 0 ? NULL : strerror(error)));
--- 211,218 ----
{
int error;
! if ((*ld_entry) == NULL ||
! (*(*ld_entry)->dlctl)(NULL, DL_GETERRNO, &error) == -1)
return "Service unavailable";
return ((char *)(error == 0 ? NULL : strerror(error)));
***************
*** 223,232 ****
void *addr;
Dl_info *dli;
{
! if (ld_entry == NULL || ld_entry->dladdr == NULL)
return (0);
! return (ld_entry->dladdr)(addr, dli);
}
/*
--- 223,232 ----
void *addr;
Dl_info *dli;
{
! if ((*ld_entry) == NULL || (*ld_entry)->dladdr == NULL)
return (0);
! return ((*ld_entry)->dladdr)(addr, dli);
}
/*
*** gnu/usr.bin/ld/rtld/rtld.c.orig Sun Oct 25 13:34:23 1998
--- gnu/usr.bin/ld/rtld/rtld.c Tue Dec 8 00:37:33 1998
***************
*** 362,367 ****
--- 362,374 ----
LM_PRIVATE(smp)->spd_refcount++;
LM_PRIVATE(smp)->spd_flags |= _RTLD_RTLD;
+ /* Fill in some field in main's __DYNAMIC structure */
+ if (version >= CRT_VERSION_BSD_4)
+ crtp->crt_ldentry = &ld_entry;
+ else
+ crtp->crt_dp->d_entry = &ld_entry;
+
+
/* Handle LD_PRELOAD's here */
ld_preload_path = getenv("LD_PRELOAD");
if (ld_preload_path != NULL)
***************
*** 376,387 ****
}
init_maps(link_map_head);
-
- /* Fill in some field in main's __DYNAMIC structure */
- if (version >= CRT_VERSION_BSD_4)
- crtp->crt_ldentry = &ld_entry;
- else
- crtp->crt_dp->d_entry = &ld_entry;
crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next;
--- 383,388 ----