diff mbox series

[04/13] elf: split _dl_map_object_from_fd() into reusable parts

Message ID 20230318165110.3672749-5-stsp2@yandex.ru
State New
Headers show
Series implement dlmem() function | expand

Commit Message

stsp March 18, 2023, 4:51 p.m. UTC
This is mostly a mechanical split, with just a very minor moves
of 2 small code fragments. This change should introduce no
functional differences.

The test-suite was run on x86_64/64 and showed no regressions.

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
---
 elf/dl-load.c | 317 ++++++++++++++++++++++++++++----------------------
 1 file changed, 175 insertions(+), 142 deletions(-)
diff mbox series

Patch

diff --git a/elf/dl-load.c b/elf/dl-load.c
index ab8b648687..9e0e63b9a3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -929,147 +929,25 @@  _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
     }
 }
 
-
-/* Map in the shared object NAME, actually located in REALNAME, and already
-   opened on FD.  */
-
-#ifndef EXTERNAL_MAP_FROM_FD
-static
-#endif
-struct link_map *
-_dl_map_object_from_fd (const char *name, const char *origname, int fd,
-			struct filebuf *fbp, char *realname,
-			struct link_map *loader, int l_type, int mode,
-			void **stack_endp, Lmid_t nsid)
+static int
+_ld_map_object_1 (struct link_map *l, int fd,
+                  struct filebuf *fbp,
+                  int mode, struct link_map *loader,
+                  void **stack_endp, int *errval_p,
+                  const char **errstring_p)
 {
-  struct link_map *l = NULL;
   const ElfW(Ehdr) *header;
   const ElfW(Phdr) *phdr;
   const ElfW(Phdr) *ph;
   size_t maplength;
   int type;
   /* Initialize to keep the compiler happy.  */
-  const char *errstring = NULL;
-  int errval = 0;
-  struct r_debug *r = _dl_debug_update (nsid);
-  bool make_consistent = false;
-
-  /* Get file information.  To match the kernel behavior, do not fill
-     in this information for the executable in case of an explicit
-     loader invocation.  */
-  struct r_file_id id;
-  if (mode & __RTLD_OPENEXEC)
-    {
-      assert (nsid == LM_ID_BASE);
-      memset (&id, 0, sizeof (id));
-    }
-  else
-    {
-      if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
-	{
-	  errstring = N_("cannot stat shared object");
-	lose_errno:
-	  errval = errno;
-	lose:
-	  /* The file might already be closed.  */
-	  if (fd != -1)
-	    __close_nocancel (fd);
-	  if (l != NULL && l->l_map_start != 0)
-	    _dl_unmap_segments (l);
-	  if (l != NULL && l->l_origin != (char *) -1l)
-	    free ((char *) l->l_origin);
-	  if (l != NULL && !l->l_libname->dont_free)
-	    free (l->l_libname);
-	  if (l != NULL && l->l_phdr_allocated)
-	    free ((void *) l->l_phdr);
-	  free (l);
-	  free (realname);
-
-	  if (make_consistent && r != NULL)
-	    {
-	      r->r_state = RT_CONSISTENT;
-	      _dl_debug_state ();
-	      LIBC_PROBE (map_failed, 2, nsid, r);
-	    }
-
-	  _dl_signal_error (errval, name, NULL, errstring);
-	}
-
-      /* Look again to see if the real name matched another already loaded.  */
-      for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
-	if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
-	  {
-	    /* The object is already loaded.
-	       Just bump its reference count and return it.  */
-	    __close_nocancel (fd);
-
-	    /* If the name is not in the list of names for this object add
-	       it.  */
-	    free (realname);
-	    add_name_to_object (l, name);
-
-	    return l;
-	  }
-    }
-
-#ifdef SHARED
-  /* When loading into a namespace other than the base one we must
-     avoid loading ld.so since there can only be one copy.  Ever.  */
-  if (__glibc_unlikely (nsid != LM_ID_BASE)
-      && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
-	  || _dl_name_match_p (name, &GL(dl_rtld_map))))
-    {
-      /* This is indeed ld.so.  Create a new link_map which refers to
-	 the real one for almost everything.  */
-      l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
-      if (l == NULL)
-	goto fail_new;
-
-      /* Refer to the real descriptor.  */
-      l->l_real = &GL(dl_rtld_map);
-
-      /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen().  */
-      l->l_addr = l->l_real->l_addr;
-      l->l_ld = l->l_real->l_ld;
-
-      /* No need to bump the refcount of the real object, ld.so will
-	 never be unloaded.  */
-      __close_nocancel (fd);
-
-      /* Add the map for the mirrored object to the object list.  */
-      _dl_add_to_namespace_list (l, nsid);
-
-      return l;
-    }
-#endif
-
-  if (mode & RTLD_NOLOAD)
-    {
-      /* We are not supposed to load the object unless it is already
-	 loaded.  So return now.  */
-      free (realname);
-      __close_nocancel (fd);
-      return NULL;
-    }
-
-  /* Print debugging message.  */
-  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
-    _dl_debug_printf ("file=%s [%lu];  generating link map\n", name, nsid);
+#define errstring (*errstring_p)
+#define errval (*errval_p)
 
   /* This is the ELF header.  We read it in `open_verify'.  */
   header = (void *) fbp->buf;
 
-  /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
-  if (__glibc_unlikely (l == NULL))
-    {
-#ifdef SHARED
-    fail_new:
-#endif
-      errstring = N_("cannot create shared object descriptor");
-      goto lose_errno;
-    }
-
   /* Extract the remaining details we need from the ELF header
      and then read in the program header table.  */
   l->l_entry = header->e_entry;
@@ -1093,7 +971,7 @@  _dl_map_object_from_fd (const char *name, const char *origname, int fd,
    /* On most platforms presume that PT_GNU_STACK is absent and the stack is
     * executable.  Other platforms default to a nonexecutable stack and don't
     * need PT_GNU_STACK to do so.  */
-   unsigned int stack_flags = DEFAULT_STACK_PERMS;
+  unsigned int stack_flags = DEFAULT_STACK_PERMS;
 
   {
     /* Scan the program header table, collecting its load commands.  */
@@ -1386,15 +1264,6 @@  cannot enable executable stack as shared object requires");
 	break;
       }
 
-  /* We are done mapping in the file.  We no longer need the descriptor.  */
-  if (__glibc_unlikely (__close_nocancel (fd) != 0))
-    {
-      errstring = N_("cannot close file descriptor");
-      goto lose_errno;
-    }
-  /* Signal that we closed the file.  */
-  fd = -1;
-
   /* Failures before this point are handled locally via lose.
      There are no more failures in this function until return,
      to change that the cleanup handling needs to be updated.  */
@@ -1419,6 +1288,23 @@  cannot enable executable stack as shared object requires");
 			   (unsigned long int) l->l_phdr,
 			   (int) sizeof (void *) * 2, l->l_phnum);
 
+  return 0;
+
+lose_errno:
+  errval = errno;
+lose:
+  return -1;
+
+#undef errval
+#undef errstring
+}
+
+static void
+_ld_map_object_2 (struct link_map *l, int mode,
+                  struct r_file_id id, const char *origname,
+                  Lmid_t nsid, struct r_debug *r,
+                  bool *make_consistent_p)
+{
   /* Set up the symbol hash table.  */
   _dl_setup_hash (l);
 
@@ -1510,7 +1396,7 @@  cannot enable executable stack as shared object requires");
       r->r_state = RT_ADD;
       _dl_debug_state ();
       LIBC_PROBE (map_start, 2, nsid, r);
-      make_consistent = true;
+      *make_consistent_p = true;
     }
   else
     assert (r->r_state == RT_ADD);
@@ -1520,10 +1406,157 @@  cannot enable executable stack as shared object requires");
   if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
     _dl_audit_objopen (l, nsid);
 #endif
+}
+
+/* Map in the shared object NAME, actually located in REALNAME, and already
+   opened on FD.  */
+
+#ifndef EXTERNAL_MAP_FROM_FD
+static
+#endif
+struct link_map *
+_dl_map_object_from_fd (const char *name, const char *origname, int fd,
+			struct filebuf *fbp, char *realname,
+			struct link_map *loader, int l_type, int mode,
+			void **stack_endp, Lmid_t nsid)
+{
+  struct link_map *l = NULL;
+  /* Initialize to keep the compiler happy.  */
+  const char *errstring = NULL;
+  int errval = 0;
+  struct r_debug *r = _dl_debug_update (nsid);
+  bool make_consistent = false;
+
+  /* Get file information.  To match the kernel behavior, do not fill
+     in this information for the executable in case of an explicit
+     loader invocation.  */
+  struct r_file_id id;
+  if (mode & __RTLD_OPENEXEC)
+    {
+      assert (nsid == LM_ID_BASE);
+      memset (&id, 0, sizeof (id));
+    }
+  else
+    {
+      if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
+	{
+	  errstring = N_("cannot stat shared object");
+	lose_errno:
+	  errval = errno;
+	lose:
+	  /* The file might already be closed.  */
+	  if (fd != -1)
+	    __close_nocancel (fd);
+	  if (l != NULL && l->l_map_start != 0)
+	    _dl_unmap_segments (l);
+	  if (l != NULL && l->l_origin != (char *) -1l)
+	    free ((char *) l->l_origin);
+	  if (l != NULL && !l->l_libname->dont_free)
+	    free (l->l_libname);
+	  if (l != NULL && l->l_phdr_allocated)
+	    free ((void *) l->l_phdr);
+	  free (l);
+	  free (realname);
+
+	  if (make_consistent && r != NULL)
+	    {
+	      r->r_state = RT_CONSISTENT;
+	      _dl_debug_state ();
+	      LIBC_PROBE (map_failed, 2, nsid, r);
+	    }
+
+	  _dl_signal_error (errval, name, NULL, errstring);
+	}
+
+      /* Look again to see if the real name matched another already loaded.  */
+      for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+	if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
+	  {
+	    /* The object is already loaded.
+	       Just bump its reference count and return it.  */
+	    __close_nocancel (fd);
+
+	    /* If the name is not in the list of names for this object add
+	       it.  */
+	    free (realname);
+	    add_name_to_object (l, name);
+
+	    return l;
+	  }
+    }
+
+#ifdef SHARED
+  /* When loading into a namespace other than the base one we must
+     avoid loading ld.so since there can only be one copy.  Ever.  */
+  if (__glibc_unlikely (nsid != LM_ID_BASE)
+      && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
+	  || _dl_name_match_p (name, &GL(dl_rtld_map))))
+    {
+      /* This is indeed ld.so.  Create a new link_map which refers to
+	 the real one for almost everything.  */
+      l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+      if (l == NULL)
+	goto fail_new;
+
+      /* Refer to the real descriptor.  */
+      l->l_real = &GL(dl_rtld_map);
+
+      /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen().  */
+      l->l_addr = l->l_real->l_addr;
+      l->l_ld = l->l_real->l_ld;
+
+      /* No need to bump the refcount of the real object, ld.so will
+	 never be unloaded.  */
+      __close_nocancel (fd);
+
+      /* Add the map for the mirrored object to the object list.  */
+      _dl_add_to_namespace_list (l, nsid);
+
+      return l;
+    }
+#endif
 
+  if (mode & RTLD_NOLOAD)
+    {
+      /* We are not supposed to load the object unless it is already
+	 loaded.  So return now.  */
+      free (realname);
+      __close_nocancel (fd);
+      return NULL;
+    }
+
+  /* Print debugging message.  */
+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+    _dl_debug_printf ("file=%s [%lu];  generating link map\n", name, nsid);
+
+  /* Enter the new object in the list of loaded objects.  */
+  l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+  if (__glibc_unlikely (l == NULL))
+    {
+#ifdef SHARED
+    fail_new:
+#endif
+      errstring = N_("cannot create shared object descriptor");
+      goto lose_errno;
+    }
+
+  if (_ld_map_object_1 (l, fd, fbp, mode, loader, stack_endp, &errval,
+                        &errstring))
+    goto lose;
+
+  /* We are done mapping in the file.  We no longer need the descriptor.  */
+  if (__glibc_unlikely (__close_nocancel (fd) != 0))
+    {
+      errstring = N_("cannot close file descriptor");
+      goto lose_errno;
+    }
+  /* Signal that we closed the file.  */
+  fd = -1;
+
+  _ld_map_object_2 (l, mode, id, origname, nsid, r, &make_consistent);
   return l;
 }
-
+
 /* Print search path.  */
 static void
 print_search_path (struct r_search_path_elem **list,