about summary refs log tree commit diff
path: root/elf/dl-load.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-06-10 20:19:39 +0000
committerRoland McGrath <roland@gnu.org>1996-06-10 20:19:39 +0000
commitba79d61b44be92bb81cba28076792a856585c4a0 (patch)
tree1ece0cbcd4568069643327ffe5da7511394e3ff8 /elf/dl-load.c
parent567c63af19d2f03836d14856596b4ae6259c03a8 (diff)
downloadglibc-ba79d61b44be92bb81cba28076792a856585c4a0.tar.gz
glibc-ba79d61b44be92bb81cba28076792a856585c4a0.tar.xz
glibc-ba79d61b44be92bb81cba28076792a856585c4a0.zip
* Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so. cvs/libc-960611
	* elf/dl-close.c: New file.
	* elf/link.h: Declare _dl_close.
	* elf/Makefile (routines): Add dl-close.
	* elf/dlclose.c (dlclose): Use _dl_close.

	* elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps.

	* elf/dl-runtime.c (_dl_global_scope): New variable.
	(_dl_object_relocation_scope): New function.
	(fixup): Use it.
	* elf/rtld.c (dl_main): Use it.
	* elf/dl-open.c (_dl_open): Use it.  If (MODE & RTLD_GLOBAL), set the
	l_global bit and append the new map to _dl_global_scope.
	* elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc,
	and _dl_object_relocation_scope.

	* elf/link.h (struct link_map): Add l_loader member.
	Remove _dl_map_object_from_fd decl.
	* elf/dl-load.c (_dl_map_object): Pass LOADER to ...
	(_dl_map_object_from_fd): Take new arg LOADER and set l_loader member.
	(_dl_map_object): Try DT_RPATH from all loaders up the chain.

	* elf/dl-object.c (_dl_loaded): Variable removed.
	(_dl_default_scope): New variable replaces it.
	* elf/link.h (_dl_loaded): Remove variable decl; instead define as
	macro for _dl_default_scope[2].
	(_dl_default_scope): Declare it.
	* sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2]
	instead of _dl_loaded.
	* sysdeps/m68k/dl-machine.h (RTLD_START): Likewise.
	* elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups.

	* elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map.
	* elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self.

	* elf/link.h (struct link_map.l_type): Remove lt_interpreter.
 	(struct link_map): Add new flag member l_global.

	* elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map
	directly instead of looking for lt_interpreter.
	* sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise.
	* elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type.
	(dl_main): Set _dl_rtld_map.l_type to lt_library.

	* elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to
	dependencies loaded, downgrading lt_executable -> lt_library.

	* elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set
	l_type from that, translating lt_library->lt_executable based on the
	file's ELF type.
	(_dl_map_object): Likewise.
	* elf/link.h: Update prototypes.
	* elf/dl-open.c: Pass type lt_loaded.
	* elf/rtld.c: Pass type lt_library.

	* elf/dl-load.c (_dl_map_object_from_fd): Handle null return from
	_dl_new_object.
	(_dl_map_object_from_fd: lose): Unchain and free L if it's not null.
	Free REALNAME, and just use NAME in error message.
	* elf/dl-object.c (_dl_new_object): If malloc fails, return null
	instead of calling _dl_signal_error.

	* elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling
	error for _dl_zerofd setup failure.

	* elf/dl-object.c (_dl_startup_loaded): Variable removed.
	* elf/link.h: Remove its decl.

	* elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it
	through to _dl_lookup_symbol.
	* elf/link.h (_dl_relocate_object): Update comment and prototype.
	* elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object.

	* elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a
	null-terminated vector of pointers, no longer a vector of exactly two.
	* elf/link.h (_dl_lookup_symbol): Update comment and prototype.

	* elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as
	done in _dl_relocate_object.

	* elf/dlopen.c: Pass "" to _dl_open when FILE is null.
Diffstat (limited to 'elf/dl-load.c')
-rw-r--r--elf/dl-load.c314
1 files changed, 166 insertions, 148 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c6acc8c222..b9f4aa184b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -63,152 +63,14 @@ int _dl_zerofd = -1;
 size_t _dl_pagesize;
 
 
-/* Try to open NAME in one of the directories in DIRPATH.
-   Return the fd, or -1.  If successful, fill in *REALNAME
-   with the malloc'd full directory name.  */
-
-static int
-open_path (const char *name, size_t namelen,
-	   const char *dirpath,
-	   char **realname)
-{
-  char *buf;
-  const char *p;
-  int fd;
-
-  p = dirpath;
-  if (p == NULL || *p == '\0')
-    {
-      errno = ENOENT;
-      return -1;
-    }
-
-  buf = __alloca (strlen (dirpath) + 1 + namelen);
-  do
-    {
-      size_t buflen;
-
-      dirpath = p;
-      p = strpbrk (dirpath, ":;");
-      if (p == NULL)
-	p = strchr (dirpath, '\0');
-
-      if (p == dirpath)
-	{
-	  /* Two adjacent colons, or a colon at the beginning or the end of
-	     the path means to search the current directory.  */
-	  (void) memcpy (buf, name, namelen);
-	  buflen = namelen;
-	}
-      else
-	{
-	  /* Construct the pathname to try.  */
-	  (void) memcpy (buf, dirpath, p - dirpath);
-	  buf[p - dirpath] = '/';
-	  (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
-	  buflen = p - dirpath + 1 + namelen;
-	}
-
-      fd = __open (buf, O_RDONLY);
-      if (fd != -1)
-	{
-	  *realname = malloc (buflen);
-	  if (*realname)
-	    {
-	      memcpy (*realname, buf, buflen);
-	      return fd;
-	    }
-	  else
-	    {
-	      /* No memory for the name, we certainly won't be able
-		 to load and link it.  */
-	      __close (fd);
-	      return -1;
-	    }
-	}
-      if (errno != ENOENT && errno != EACCES)
-	/* The file exists and is readable, but something went wrong.  */
-	return -1;
-    }
-  while (*p++ != '\0');
-
-  return -1;
-}
-
-/* Map in the shared object file NAME.  */
-
-struct link_map *
-_dl_map_object (struct link_map *loader, const char *name)
-{
-  int fd;
-  char *realname;
-  struct link_map *l;
-
-  /* Look for this name among those already loaded.  */
-  for (l = _dl_loaded; l; l = l->l_next)
-    if (! strcmp (name, l->l_libname))
-      {
-	/* The object is already loaded.
-	   Just bump its reference count and return it.  */
-	++l->l_opencount;
-	return l;
-      }
-
-  if (strchr (name, '/') == NULL)
-    {
-      /* Search for NAME in several places.  */
-
-      size_t namelen = strlen (name) + 1;
-
-      inline void trypath (const char *dirpath)
-	{
-	  fd = open_path (name, namelen, dirpath, &realname);
-	}
-
-      fd = -1;
-      if (loader && loader->l_info[DT_RPATH])
-	trypath ((const char *) (loader->l_addr +
-				 loader->l_info[DT_STRTAB]->d_un.d_ptr +
-				 loader->l_info[DT_RPATH]->d_un.d_val));
-      if (fd == -1 && ! _dl_secure)
-	trypath (getenv ("LD_LIBRARY_PATH"));
-      if (fd == -1)
-	{
-	  extern const char *_dl_rpath;	/* Set in rtld.c. */
-	  trypath (_dl_rpath);
-	}
-    }
-  else
-    {
-      fd = __open (name, O_RDONLY);
-      if (fd != -1)
-	{
-	  size_t len = strlen (name) + 1;
-	  realname = malloc (len);
-	  if (realname)
-	    memcpy (realname, name, len);
-	  else
-	    {
-	      __close (fd);
-	      fd = -1;
-	    }
-	}
-    }
-
-  if (fd == -1)
-    _dl_signal_error (errno, name, "cannot open shared object file");
-
-  return _dl_map_object_from_fd (name, fd, realname);
-}
-
-
 /* Map in the shared object NAME, actually located in REALNAME, and already
    opened on FD.  */
 
 struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, char *realname)
+_dl_map_object_from_fd (const char *name, int fd, char *realname,
+			struct link_map *loader, int l_type)
 {
-  struct link_map *l = NULL;
+  struct link_map *l;
   void *file_mapping = NULL;
   size_t mapping_size = 0;
 
@@ -218,7 +80,17 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
       (void) __close (fd);
       if (file_mapping)
 	__munmap (file_mapping, mapping_size);
-      _dl_signal_error (code, l ? l->l_name : name, msg);
+      if (l)
+	{
+	  /* Remove the stillborn object from the list and free it.  */
+	  if (l->l_prev)
+	    l->l_prev->l_next = l->l_next;
+	  if (l->l_next)
+	    l->l_next->l_prev = l->l_prev;
+	  free (l);
+	}
+      free (realname);
+      _dl_signal_error (code, name, msg);
     }
 
   inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len,
@@ -304,17 +176,23 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
   if (header->e_phentsize != sizeof (ElfW(Phdr)))
     LOSE ("ELF file's phentsize not the expected size");
 
-  /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, lt_loaded);
-  l->l_opencount = 1;
-
   if (_dl_zerofd == -1)
     {
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
-	_dl_signal_error (errno, NULL, "cannot open zero fill device");
+	{
+	  __close (fd);
+	  _dl_signal_error (errno, NULL, "cannot open zero fill device");
+	}
     }
 
+  /* Enter the new object in the list of loaded objects.  */
+  l = _dl_new_object (realname, name, l_type);
+  if (! l)
+    lose (ENOMEM, "cannot create shared object descriptor");
+  l->l_opencount = 1;
+  l->l_loader = loader;
+
   /* Extract the remaining details we need from the ELF header
      and then map in the program header table.  */
   l->l_entry = header->e_entry;
@@ -464,7 +342,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
   /* We are done mapping in the file.  We no longer need the descriptor.  */
   __close (fd);
 
-  l->l_type = type == ET_EXEC ? lt_executable : lt_library;
+  if (l->l_type == lt_library && type == ET_EXEC)
+    l->l_type = lt_executable;
 
   if (l->l_ld == 0)
     {
@@ -484,3 +363,142 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
 
   return l;
 }
+
+/* Try to open NAME in one of the directories in DIRPATH.
+   Return the fd, or -1.  If successful, fill in *REALNAME
+   with the malloc'd full directory name.  */
+
+static int
+open_path (const char *name, size_t namelen,
+	   const char *dirpath,
+	   char **realname)
+{
+  char *buf;
+  const char *p;
+  int fd;
+
+  p = dirpath;
+  if (p == NULL || *p == '\0')
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  buf = __alloca (strlen (dirpath) + 1 + namelen);
+  do
+    {
+      size_t buflen;
+
+      dirpath = p;
+      p = strpbrk (dirpath, ":;");
+      if (p == NULL)
+	p = strchr (dirpath, '\0');
+
+      if (p == dirpath)
+	{
+	  /* Two adjacent colons, or a colon at the beginning or the end of
+	     the path means to search the current directory.  */
+	  (void) memcpy (buf, name, namelen);
+	  buflen = namelen;
+	}
+      else
+	{
+	  /* Construct the pathname to try.  */
+	  (void) memcpy (buf, dirpath, p - dirpath);
+	  buf[p - dirpath] = '/';
+	  (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
+	  buflen = p - dirpath + 1 + namelen;
+	}
+
+      fd = __open (buf, O_RDONLY);
+      if (fd != -1)
+	{
+	  *realname = malloc (buflen);
+	  if (*realname)
+	    {
+	      memcpy (*realname, buf, buflen);
+	      return fd;
+	    }
+	  else
+	    {
+	      /* No memory for the name, we certainly won't be able
+		 to load and link it.  */
+	      __close (fd);
+	      return -1;
+	    }
+	}
+      if (errno != ENOENT && errno != EACCES)
+	/* The file exists and is readable, but something went wrong.  */
+	return -1;
+    }
+  while (*p++ != '\0');
+
+  return -1;
+}
+
+/* Map in the shared object file NAME.  */
+
+struct link_map *
+_dl_map_object (struct link_map *loader, const char *name, int type)
+{
+  int fd;
+  char *realname;
+  struct link_map *l;
+
+  /* Look for this name among those already loaded.  */
+  for (l = _dl_loaded; l; l = l->l_next)
+    if (! strcmp (name, l->l_libname))
+      {
+	/* The object is already loaded.
+	   Just bump its reference count and return it.  */
+	++l->l_opencount;
+	return l;
+      }
+
+  if (strchr (name, '/') == NULL)
+    {
+      /* Search for NAME in several places.  */
+
+      size_t namelen = strlen (name) + 1;
+
+      inline void trypath (const char *dirpath)
+	{
+	  fd = open_path (name, namelen, dirpath, &realname);
+	}
+
+      fd = -1;
+      for (l = loader; l; l = l->l_loader)
+	if (l && l->l_info[DT_RPATH])
+	  trypath ((const char *) (l->l_addr +
+				   l->l_info[DT_STRTAB]->d_un.d_ptr +
+				   l->l_info[DT_RPATH]->d_un.d_val));
+      if (fd == -1 && ! _dl_secure)
+	trypath (getenv ("LD_LIBRARY_PATH"));
+      if (fd == -1)
+	{
+	  extern const char *_dl_rpath;	/* Set in rtld.c. */
+	  trypath (_dl_rpath);
+	}
+    }
+  else
+    {
+      fd = __open (name, O_RDONLY);
+      if (fd != -1)
+	{
+	  size_t len = strlen (name) + 1;
+	  realname = malloc (len);
+	  if (realname)
+	    memcpy (realname, name, len);
+	  else
+	    {
+	      __close (fd);
+	      fd = -1;
+	    }
+	}
+    }
+
+  if (fd == -1)
+    _dl_signal_error (errno, name, "cannot open shared object file");
+
+  return _dl_map_object_from_fd (name, fd, realname, loader, type);
+}