l->l_prev->l_next = l->l_next; if (l->l_next) l->l_next->l_prev = l->l_prev;
rtld_map.l_prev->l_next = rtld_map.l_next; if (rtld_map.l_next) rtld_map.l_next->l_prev = rtld_map.l_prev;
dl_main (const Elf32_Phdr *phdr,	 Elf32_Word phent,	 Elf32_Addr *user_entry){  void doit (void)    {      const Elf32_Phdr *ph;      struct link_map *l;      const char *interpreter_name;      int lazy;      int list_only = 0;      if (*user_entry == (Elf32_Addr) &_start)	{	  /* Ho ho.  We are not the program interpreter!  We are the program	     itself!  This means someone ran ld.so as a command.  Well, that	     might be convenient to do sometimes.  We support it by	     interpreting the args like this:	     	     ld.so PROGRAM ARGS...	     	     The first argument is the name of a file containing an ELF	     executable we will load and run with the following arguments.	     To simplify life here, PROGRAM is searched for using the	     normal rules for shared objects, rather than $PATH or anything	     like that.  We just load it and use its entry point; we don't	     pay attention to its PT_INTERP command (we are the interpreter	     ourselves).  This is an easy way to test a new ld.so before	     installing it.  */	  if (_dl_argc < 2)	    _dl_sysdep_fatal ("\Usage: ld.so [--list] EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\You have invoked `ld.so', the helper program for shared library executables.\n\This program usually lives in the file `/lib/ld.so', and special directives\n\in executable files using ELF shared libraries tell the system's program\n\loader to load the helper program from this file.  This helper program loads\n\the shared libraries needed by the program executable, prepares the program\n\to run, and runs it.  You may invoke this helper program directly from the\n\command line to load and run an ELF executable file; this is like executing\n\that file itself, but always uses this helper program from the file you\n\specified, instead of the helper program file specified in the executable\n\file you run.  This is mostly of use for maintainers to test new versions\n\of this helper program; chances are you did not intend to run this program.\n",			      NULL);	  interpreter_name = _dl_argv[0];	  if (! strcmp (_dl_argv[1], "--list"))	    {	      list_only = 1;	      ++_dl_skip_args;	      --_dl_argc;	      ++_dl_argv;	    }	  ++_dl_skip_args;	  --_dl_argc;	  ++_dl_argv;	  l = _dl_map_object (NULL, _dl_argv[0]);	  phdr = l->l_phdr;	  phent = l->l_phnum;	  l->l_type = lt_executable;	  l->l_libname = (char *) "";	  *user_entry = l->l_entry;	}      else	{	  /* Create a link_map for the executable itself.	     This will be what dlopen on "" returns.  */	  l = _dl_new_object ((char *) "", "", lt_executable);	  l->l_phdr = phdr;	  l->l_phnum = phent;	  interpreter_name = 0;	  l->l_entry = *user_entry;	}      if (l != _dl_loaded)	{	  /* GDB assumes that the first element on the chain is the	     link_map for the executable itself, and always skips it.	     Make sure the first one is indeed that one.  */	  l->l_prev->l_next = l->l_next;	  if (l->l_next)	    l->l_next->l_prev = l->l_prev;	  l->l_prev = NULL;	  l->l_next = _dl_loaded;	  _dl_loaded->l_prev = l;	  _dl_loaded = l;	}      /* Scan the program header table for the dynamic section.  */      for (ph = phdr; ph < &phdr[phent]; ++ph)	switch (ph->p_type)	  {	  case PT_DYNAMIC:	    /* This tells us where to find the dynamic section,	       which tells us everything we need to do.  */	    l->l_ld = (void *) l->l_addr + ph->p_vaddr;	    break;	  case PT_INTERP:	    /* This "interpreter segment" was used by the program loader to	       find the program interpreter, which is this program itself, the	       dynamic linker.  We note what name finds us, so that a future	       dlopen call or DT_NEEDED entry, for something that wants to link	       against the dynamic linker as a shared library, will know that	       the shared object is already loaded.  */	    interpreter_name = (void *) l->l_addr + ph->p_vaddr;	    break;	  }      assert (interpreter_name); /* How else did we get here?  */      /* Extract the contents of the dynamic section for easy access.  */      elf_get_dynamic_info (l->l_ld, l->l_info);      /* Set up our cache of pointers into the hash table.  */      _dl_setup_hash (l);      if (l->l_info[DT_DEBUG])	/* There is a DT_DEBUG entry in the dynamic section.  Fill it in	   with the run-time address of the r_debug structure, which we	   will set up later to communicate with the debugger.  */	l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;      l = _dl_new_object ((char *) interpreter_name, interpreter_name,			  lt_interpreter);      /* Now process all the DT_NEEDED entries and map in the objects.	 Each new link_map will go on the end of the chain, so we will	 come across it later in the loop to map in its dependencies.  */      for (l = _dl_loaded; l; l = l->l_next)	{	  if (l->l_info[DT_NEEDED])	    {	      const char *strtab		= (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;	      const Elf32_Dyn *d;	      for (d = l->l_ld; d->d_tag != DT_NULL; ++d)		if (d->d_tag == DT_NEEDED)		  _dl_map_object (l, strtab + d->d_un.d_val);	    }	  l->l_deps_loaded = 1;	}      l = _dl_loaded->l_next;      while (l->l_type != lt_interpreter)	l = l->l_next;      if (l->l_opencount == 0)	{	  /* No DT_NEEDED entry referred to the interpreter object itself.	     Remove it from the maps we will use for symbol resolution.  */	  l->l_prev->l_next = l->l_next;	  if (l->l_next)	    l->l_next->l_prev = l->l_prev;	}      lazy = !_dl_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';      /* Now we have all the objects loaded.  Relocate them all.	 We do this in reverse order so that copy relocs of earlier	 objects overwrite the data written by later objects.  */      l = _dl_loaded;      while (l->l_next)	l = l->l_next;      do	{	  _dl_relocate_object (l, lazy);	  l = l->l_prev;	} while (l);      /* Tell the debugger where to find the map of loaded objects.  */      dl_r_debug.r_version = 1	/* R_DEBUG_VERSION XXX */;      dl_r_debug.r_map = _dl_loaded;      dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;      if (list_only)	{	  if (! _dl_loaded->l_info[DT_NEEDED])	    {	      _dl_sysdep_message (_dl_loaded->l_name, ": statically linked\n",				  NULL);	      _exit (1);	    }	  for (l = _dl_loaded->l_next; l; l = l->l_next)	    {	      char buf[20], *bp;	      buf[sizeof buf - 1] = '\0';	      bp = _itoa (l->l_addr, &buf[sizeof buf - 1], 16, 0);	      while (&buf[sizeof buf - 1] - bp < sizeof l->l_addr * 2)		*--bp = '0';	      _dl_sysdep_message ("\t", l->l_libname, " => ", l->l_name,				  " (0x", bp, ")\n", NULL);	    }	  _exit (0);	}    }  const char *errstring;  const char *errobj;  int err;  err = _dl_catch_error (&errstring, &errobj, &doit);  if (errstring)    _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>",		      ": error in loading shared libraries\n",		      errobj ?: "", errobj ? ": " : "",		      errstring, err ? ": " : "",		      err ? strerror (err) : "", "\n", NULL);  /* Once we return, _dl_sysdep_start will invoke     the DT_INIT functions and then *USER_ENTRY.  */}