somewhere, and that the first load command starts at the beginning of the file and thus contains the ELF file header.  */ ElfW(Addr) bof = l->l_addr + loadcmds[0].mapstart; assert (loadcmds[0].mapoff == 0); l->l_phdr = (void *) (bof + ((const ElfW(Ehdr) *) bof)->e_phoff);
somewhere.  */ for (c = loadcmds; c < &loadcmds[nloadcmds]; c++) if (c->mapoff <= header->e_phoff && (c->mapend - c->mapstart + c->mapoff >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr)))) { ElfW(Addr) bof = l->l_addr + c->mapstart; l->l_phdr = (void *) (bof + header->e_phoff - c->mapoff); break; } if (l->l_phdr == 0) LOSE ("program headers not contained in any loaded segment");
_dl_map_object_from_fd (const char *name, int fd, char *realname,			struct link_map *loader, int l_type){  struct link_map *l = NULL;#define LOSE(s) lose (0, (s))  void lose (int code, const char *msg)    {      (void) __close (fd);      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,			      int prot, int fixed, off_t offset)    {      caddr_t mapat = __mmap ((caddr_t) mapstart, len, prot,			      fixed|MAP_COPY|MAP_FILE,			      fd, offset);      if (mapat == MAP_FAILED)	lose (errno, "failed to map segment from shared object");      return mapat;    }  const ElfW(Ehdr) *header;  const ElfW(Phdr) *phdr;  const ElfW(Phdr) *ph;  size_t maplength;  int type;  char *readbuf;  ssize_t readlength;  /* Look again to see if the real name matched another already loaded.  */  for (l = _dl_loaded; l; l = l->l_next)    if (! strcmp (realname, l->l_name))      {	/* The object is already loaded.	   Just bump its reference count and return it.  */	__close (fd);	/* If the name is not in the list of names for this object add	   it.  */	free (realname);	add_name_to_object (l, name);	++l->l_opencount;	return l;      }  /* Print debugging message.  */  if (_dl_debug_files)    _dl_debug_message (1, "file=", name, ";  generating link map\n", NULL);  /* Read the header directly.  */  readbuf = alloca (_dl_pagesize);  readlength = __libc_read (fd, readbuf, _dl_pagesize);  if (readlength < (ssize_t) sizeof(*header))    lose (errno, "cannot read file data");  header = (void *) readbuf;  /* Check the header for basic validity.  */  if (*(Elf32_Word *) &header->e_ident !=#if BYTE_ORDER == LITTLE_ENDIAN      ((ELFMAG0 << (EI_MAG0 * 8)) |       (ELFMAG1 << (EI_MAG1 * 8)) |       (ELFMAG2 << (EI_MAG2 * 8)) |       (ELFMAG3 << (EI_MAG3 * 8)))#else      ((ELFMAG0 << (EI_MAG3 * 8)) |       (ELFMAG1 << (EI_MAG2 * 8)) |       (ELFMAG2 << (EI_MAG1 * 8)) |       (ELFMAG3 << (EI_MAG0 * 8)))#endif      )    LOSE ("invalid ELF header");#define ELF32_CLASS ELFCLASS32#define ELF64_CLASS ELFCLASS64  if (header->e_ident[EI_CLASS] != ELFW(CLASS))    LOSE ("ELF file class not " STRING(__ELF_NATIVE_CLASS) "-bit");  if (header->e_ident[EI_DATA] != byteorder)    LOSE ("ELF file data encoding not " byteorder_name);  if (header->e_ident[EI_VERSION] != EV_CURRENT)    LOSE ("ELF file version ident not " STRING(EV_CURRENT));  /* XXX We should be able so set system specific versions which are     allowed here.  */  if (header->e_ident[EI_OSABI] != ELFOSABI_SYSV)    LOSE ("ELF file OS ABI not " STRING(ELFOSABI_SYSV));  if (header->e_ident[EI_ABIVERSION] != 0)    LOSE ("ELF file ABI version not 0");  if (header->e_version != EV_CURRENT)    LOSE ("ELF file version not " STRING(EV_CURRENT));  if (! elf_machine_matches_host (header->e_machine))    LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);  if (header->e_phentsize != sizeof (ElfW(Phdr)))    LOSE ("ELF file's phentsize not the expected size");#ifndef MAP_ANON#define MAP_ANON 0  if (_dl_zerofd == -1)    {      _dl_zerofd = _dl_sysdep_open_zero_fill ();      if (_dl_zerofd == -1)	{	  __close (fd);	  _dl_signal_error (errno, NULL, "cannot open zero fill device");	}    }#endif  /* Enter the new object in the list of loaded objects.  */  l = _dl_new_object (realname, name, l_type, loader);  if (! l)    lose (ENOMEM, "cannot create shared object descriptor");  l->l_opencount = 1;  /* Extract the remaining details we need from the ELF header     and then read in the program header table.  */  l->l_entry = header->e_entry;  type = header->e_type;  l->l_phnum = header->e_phnum;  maplength = header->e_phnum * sizeof (ElfW(Phdr));  if (header->e_phoff + maplength <= readlength)    phdr = (void *) (readbuf + header->e_phoff);  else    {      phdr = alloca (maplength);      __lseek (fd, SEEK_SET, header->e_phoff);      if (__libc_read (fd, (void *) phdr, maplength) != maplength)        lose (errno, "cannot read file data");    }  {    /* Scan the program header table, collecting its load commands.  */    struct loadcmd      {	ElfW(Addr) mapstart, mapend, dataend, allocend;	off_t mapoff;	int prot;      } loadcmds[l->l_phnum], *c;    size_t nloadcmds = 0;    l->l_ld = 0;    l->l_phdr = 0;    l->l_addr = 0;    for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)      switch (ph->p_type)	{	  /* These entries tell us where to find things once the file's	     segments are mapped in.  We record the addresses it says	     verbatim, and later correct for the run-time load address.  */	case PT_DYNAMIC:	  l->l_ld = (void *) ph->p_vaddr;	  break;	case PT_PHDR:	  l->l_phdr = (void *) ph->p_vaddr;	  break;	case PT_LOAD:	  /* A load command tells us to map in part of the file.	     We record the load commands and process them all later.  */	  if (ph->p_align % _dl_pagesize != 0)	    LOSE ("ELF load command alignment not page-aligned");	  if ((ph->p_vaddr - ph->p_offset) % ph->p_align)	    LOSE ("ELF load command address/offset not properly aligned");	  {	    struct loadcmd *c = &loadcmds[nloadcmds++];	    c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);	    c->mapend = ((ph->p_vaddr + ph->p_filesz + _dl_pagesize - 1)			 & ~(_dl_pagesize - 1));	    c->dataend = ph->p_vaddr + ph->p_filesz;	    c->allocend = ph->p_vaddr + ph->p_memsz;	    c->mapoff = ph->p_offset & ~(ph->p_align - 1);	    c->prot = 0;	    if (ph->p_flags & PF_R)	      c->prot |= PROT_READ;	    if (ph->p_flags & PF_W)	      c->prot |= PROT_WRITE;	    if (ph->p_flags & PF_X)	      c->prot |= PROT_EXEC;	    break;	  }	}    /* Now process the load commands and map segments into memory.  */    c = loadcmds;    /* Length of the sections to be loaded.  */    maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;    if (type == ET_DYN || type == ET_REL)      {	/* This is a position-independent shared object.  We can let the	   kernel map it anywhere it likes, but we must have space for all	   the segments in their specified positions relative to the first.	   So we map the first segment without MAP_FIXED, but with its	   extent increased to cover all the segments.  Then we remove	   access from excess portion, and there is known sufficient space	   there to remap from the later segments.	   As a refinement, sometimes we have an address that we would	   prefer to map such objects at; but this is only a preference,	   the OS can do whatever it likes. */ 	caddr_t mapat;	ElfW(Addr) mappref;	mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart)		   - MAP_BASE_ADDR (l));	mapat = map_segment (mappref, maplength, c->prot, 0, c->mapoff);	l->l_addr = (ElfW(Addr)) mapat - c->mapstart;	/* Change protection on the excess portion to disallow all access;	   the portions we do not remap later will be inaccessible as if	   unallocated.  Then jump into the normal segment-mapping loop to	   handle the portion of the segment past the end of the file	   mapping.  */	__mprotect ((caddr_t) (l->l_addr + c->mapend),		    loadcmds[nloadcmds - 1].allocend - c->mapend,		    0);	/* Remember which part of the address space this object uses.  */	l->l_map_start = c->mapstart + l->l_addr;	l->l_map_end = l->l_map_start + maplength;	goto postmap;      }    else      {	/* Notify ELF_PREFERRED_ADDRESS that we have to load this one	   fixed.  */	ELF_FIXED_ADDRESS (loader, c->mapstart);      }    /* Remember which part of the address space this object uses.  */    l->l_map_start = c->mapstart + l->l_addr;    l->l_map_end = l->l_map_start + maplength;    while (c < &loadcmds[nloadcmds])      {	if (c->mapend > c->mapstart)	  /* Map the segment contents from the file.  */	  map_segment (l->l_addr + c->mapstart, c->mapend - c->mapstart,		       c->prot, MAP_FIXED, c->mapoff);      postmap:	if (c->allocend > c->dataend)	  {	    /* Extra zero pages should appear at the end of this segment,	       after the data mapped from the file.   */	    ElfW(Addr) zero, zeroend, zeropage;	    zero = l->l_addr + c->dataend;	    zeroend = l->l_addr + c->allocend;	    zeropage = (zero + _dl_pagesize - 1) & ~(_dl_pagesize - 1);	    if (zeroend < zeropage)	      /* All the extra data is in the last page of the segment.		 We can just zero it.  */	      zeropage = zeroend;	    if (zeropage > zero)	      {		/* Zero the final part of the last page of the segment.  */		if ((c->prot & PROT_WRITE) == 0)		  {		    /* Dag nab it.  */		    if (__mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)),				    _dl_pagesize, c->prot|PROT_WRITE) < 0)		      lose (errno, "cannot change memory protections");		  }		memset ((void *) zero, 0, zeropage - zero);		if ((c->prot & PROT_WRITE) == 0)		  __mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)),			      _dl_pagesize, c->prot);	      }	    if (zeroend > zeropage)	      {		/* Map the remaining zero pages in from the zero fill FD.  */		caddr_t mapat;		mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,				c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,				ANONFD, 0);		if (mapat == MAP_FAILED)		  lose (errno, "cannot map zero-fill pages");	      }	  }	++c;      }    if (l->l_phdr == 0)      {	/* There was no PT_PHDR specified.  We need to find the phdr in the           load image ourselves.  We assume it is in fact in the load image           somewhere, and that the first load command starts at the           beginning of the file and thus contains the ELF file header.  */	ElfW(Addr) bof = l->l_addr + loadcmds[0].mapstart;	assert (loadcmds[0].mapoff == 0);	l->l_phdr = (void *) (bof + ((const ElfW(Ehdr) *) bof)->e_phoff);      }    else      /* Adjust the PT_PHDR value by the runtime load address.  */      (ElfW(Addr)) l->l_phdr += l->l_addr;  }  /* We are done mapping in the file.  We no longer need the descriptor.  */  __close (fd);  if (l->l_type == lt_library && type == ET_EXEC)    l->l_type = lt_executable;  if (l->l_ld == 0)    {      if (type == ET_DYN)	LOSE ("object file has no dynamic section");    }  else    (ElfW(Addr)) l->l_ld += l->l_addr;  l->l_entry += l->l_addr;  if (_dl_debug_files)    {      const size_t nibbles = sizeof (void *) * 2;      char buf1[nibbles + 1];      char buf2[nibbles + 1];      char buf3[nibbles + 1];      buf1[nibbles] = '\0';      buf2[nibbles] = '\0';      buf3[nibbles] = '\0';      memset (buf1, '0', nibbles);      memset (buf2, '0', nibbles);      memset (buf3, '0', nibbles);      _itoa_word ((unsigned long int) l->l_ld, &buf1[nibbles], 16, 0);      _itoa_word ((unsigned long int) l->l_addr, &buf2[nibbles], 16, 0);      _itoa_word (maplength, &buf3[nibbles], 16, 0);      _dl_debug_message (1, "  dynamic: 0x", buf1, "  base: 0x", buf2,			 "   size: 0x", buf3, "\n", NULL);      memset (buf1, '0', nibbles);      memset (buf2, '0', nibbles);      memset (buf3, ' ', nibbles);      _itoa_word ((unsigned long int) l->l_entry, &buf1[nibbles], 16, 0);      _itoa_word ((unsigned long int) l->l_phdr, &buf2[nibbles], 16, 0);      _itoa_word (l->l_phnum, &buf3[nibbles], 10, 0);      _dl_debug_message (1, "    entry: 0x", buf1, "  phdr: 0x", buf2,			 "  phnum:   ", buf3, "\n\n", NULL);    }  elf_get_dynamic_info (l->l_ld, l->l_info);  if (l->l_info[DT_HASH])    _dl_setup_hash (l);  /* If this object has DT_SYMBOLIC set modify now its scope.  We don't     have to do this for the main map.  */  if (l->l_info[DT_SYMBOLIC] && &l->l_searchlist != l->l_scope[0])    {      /* Create an appropriate searchlist.  It contains only this map.	 XXX This is the definition of DT_SYMBOLIC in SysVr4.  The old	 GNU ld.so implementation had a different interpretation which	 is more reasonable.  We are prepared to add this possibility	 back as part of a GNU extension of the ELF format.  */      l->l_symbolic_searchlist.r_list =	(struct link_map **) malloc (sizeof (struct link_map *));      if (l->l_symbolic_searchlist.r_list == NULL)	lose (ENOMEM, "cannot create searchlist");      l->l_symbolic_searchlist.r_list[0] = l;      l->l_symbolic_searchlist.r_nlist = 1;      l->l_symbolic_searchlist.r_duplist = l->l_symbolic_searchlist.r_list;      l->l_symbolic_searchlist.r_nduplist = 1;      /* Now move the existing entries one back.  */      memmove (&l->l_scope[1], &l->l_scope[0],	       3 * sizeof (struct r_scope_elem *));      /* Now add the new entry.  */      l->l_scope[0] = &l->l_symbolic_searchlist;    }  return l;}/* Print search path.  */static voidprint_search_path (struct r_search_path_elem **list,                   const char *what, const char *name){  char buf[max_dirnamelen + max_capstrlen];  int first = 1;  _dl_debug_message (1, " search path=", NULL);  while (*list != NULL && (*list)->what == what) /* Yes, ==.  */    {      char *endp = __mempcpy (buf, (*list)->dirname, (*list)->dirnamelen);      size_t cnt;      for (cnt = 0; cnt < ncapstr; ++cnt)	if ((*list)->status[cnt] != nonexisting)	  {	    char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len);	    if (cp == buf || (cp == buf + 1 && buf[0] == '/'))	      cp[0] = '\0';	    else	      cp[-1] = '\0';	    _dl_debug_message (0, first ? "" : ":", buf, NULL);	    first = 0;	  }      ++list;    }  if (name != NULL)    _dl_debug_message (0, "\t\t(", what, " from file ",			name[0] ? name : _dl_argv[0], ")\n", NULL);  else    _dl_debug_message (0, "\t\t(", what, ")\n", NULL);}/* Try to open NAME in one of the directories in DIRS.   Return the fd, or -1.  If successful, fill in *REALNAME   with the malloc'd full directory name.  */static intopen_path (const char *name, size_t namelen, int preloaded,	   struct r_search_path_elem **dirs,	   char **realname){  char *buf;  int fd = -1;  const char *current_what = NULL;  if (dirs == NULL || *dirs == NULL)    {      __set_errno (ENOENT);      return -1;    }  buf = alloca (max_dirnamelen + max_capstrlen + namelen);  do    {      struct r_search_path_elem *this_dir = *dirs;      size_t buflen = 0;      size_t cnt;      char *edp;      /* If we are debugging the search for libraries print the path	 now if it hasn't happened now.  */      if (_dl_debug_libs && current_what != this_dir->what)	{	  current_what = this_dir->what;	  print_search_path (dirs, current_what, this_dir->where);	}      edp = (char *) __mempcpy (buf, this_dir->dirname, this_dir->dirnamelen);      for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt)	{	  /* Skip this directory if we know it does not exist.  */	  if (this_dir->status[cnt] == nonexisting)	    continue;	  buflen =	    ((char *) __mempcpy (__mempcpy (edp,					    capstr[cnt].str, capstr[cnt].len),				 name, namelen)	     - buf);	  /* Print name we try if this is wanted.  */	  if (_dl_debug_libs)	    _dl_debug_message (1, "  trying file=", buf, "\n", NULL);	  fd = __open (buf, O_RDONLY);	  if (this_dir->status[cnt] == unknown)	    {	      if (fd != -1)		this_dir->status[cnt] = existing;	      else		{		  /* We failed to open machine dependent library.  Let's		     test whether there is any directory at all.  */		  struct stat st;		  buf[buflen - namelen - 1] = '\0';		  if (__xstat (_STAT_VER, buf, &st) != 0		      || ! S_ISDIR (st.st_mode))		    /* The directory does not exist or it is no directory.  */		    this_dir->status[cnt] = nonexisting;		  else		    this_dir->status[cnt] = existing;		}	    }	  if (fd != -1 && preloaded && __libc_enable_secure)	    {	      /* This is an extra security effort to make sure nobody can		 preload broken shared objects which are in the trusted		 directories and so exploit the bugs.  */	      struct stat st;	      if (__fxstat (_STAT_VER, fd, &st) != 0		  || (st.st_mode & S_ISUID) == 0)		{		  /* The shared object cannot be tested for being SUID		     or this bit is not set.  In this case we must not		     use this object.  */		  __close (fd);		  fd = -1;		  /* We simply ignore the file, signal this by setting		     the error value which would have been set by `open'.  */		  errno = ENOENT;		}	    }	}      if (fd != -1)	{	  *realname = malloc (buflen);	  if (*realname != NULL)	    {	      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 (*++dirs != NULL);  return -1;}/* Map in the shared object file NAME.  */struct link_map *internal_function_dl_map_object (struct link_map *loader, const char *name, int preloaded,		int type, int trace_mode){  int fd;  char *realname;  char *name_copy;  struct link_map *l;  /* Look for this name among those already loaded.  */  for (l = _dl_loaded; l; l = l->l_next)    {      /* If the requested name matches the soname of a loaded object,	 use that object.  Elide this check for names that have not	 yet been opened.  */      if (l->l_opencount <= 0)	continue;      if (!_dl_name_match_p (name, l))	{	  const char *soname;	  if (l->l_info[DT_SONAME] == NULL)	    continue;	  soname = (const char *) (l->l_addr				   + l->l_info[DT_STRTAB]->d_un.d_ptr				   + l->l_info[DT_SONAME]->d_un.d_val);	  if (strcmp (name, soname) != 0)	    continue;	  /* We have a match on a new name -- cache it.  */	  add_name_to_object (l, soname);	}      /* We have a match -- bump the reference count and return it.  */      ++l->l_opencount;      return l;    }  /* Display information if we are debugging.  */  if (_dl_debug_files && loader != NULL)    _dl_debug_message (1, "\nfile=", name, ";  needed by ",		       loader->l_name[0] ? loader->l_name : _dl_argv[0],		       "\n", NULL);  if (strchr (name, '/') == NULL)    {      /* Search for NAME in several places.  */      size_t namelen = strlen (name) + 1;      if (_dl_debug_libs)	_dl_debug_message (1, "find library=", name, "; searching\n", NULL);      fd = -1;      /* First try the DT_RPATH of the dependent object that caused NAME	 to be loaded.  Then that object's dependent, and on up.  */      for (l = loader; fd == -1 && l; l = l->l_loader)	if (l && l->l_info[DT_RPATH])	  {	    /* Make sure the cache information is available.  */	    if (l->l_rpath_dirs == NULL)	      {		size_t ptrval = (l->l_addr				 + l->l_info[DT_STRTAB]->d_un.d_ptr				 + l->l_info[DT_RPATH]->d_un.d_val);		l->l_rpath_dirs =		  decompose_rpath ((const char *) ptrval, l);	      }	    if (l->l_rpath_dirs != NULL)	      fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,			      &realname);	  }      /* If dynamically linked, try the DT_RPATH of the executable itself.  */      l = _dl_loaded;      if (fd == -1 && l && l->l_type != lt_loaded && l != loader	  && l->l_rpath_dirs != NULL)	fd = open_path (name, namelen, preloaded, l->l_rpath_dirs, &realname);      /* Try the LD_LIBRARY_PATH environment variable.  */      if (fd == -1 && env_path_list != NULL)	fd = open_path (name, namelen, preloaded, env_path_list, &realname);      if (fd == -1)	{	  /* Check the list of libraries in the file /etc/ld.so.cache,	     for compatibility with Linux's ldconfig program.  */	  extern const char *_dl_load_cache_lookup (const char *name);	  const char *cached = _dl_load_cache_lookup (name);	  if (cached)	    {	      fd = __open (cached, O_RDONLY);	      if (fd != -1)		{		  realname = local_strdup (cached);		  if (realname == NULL)		    {		      __close (fd);		      fd = -1;		    }		}	    }	}      /* Finally, try the default path.  */      if (fd == -1)	fd = open_path (name, namelen, preloaded, rtld_search_dirs, &realname);      /* Add another newline when we a tracing the library loading.  */      if (_dl_debug_libs)        _dl_debug_message (1, "\n", NULL);    }  else    {      /* The path may contain dynamic string tokens.  */      realname = (loader		  ? expand_dynamic_string_token (loader, name)		  : local_strdup (name));      if (realname == NULL)	fd = -1;      else	{	  fd = __open (realname, O_RDONLY);	  if (fd == -1)	    free (realname);	}    }  if (fd == -1)    {      if (trace_mode)	{	  /* We haven't found an appropriate library.  But since we	     are only interested in the list of libraries this isn't	     so severe.  Fake an entry with all the information we	     have.  */	  static const ElfW(Symndx) dummy_bucket = STN_UNDEF;	  /* Enter the new object in the list of loaded objects.  */	  if ((name_copy = local_strdup (name)) == NULL	      || (l = _dl_new_object (name_copy, name, type, loader)) == NULL)	    _dl_signal_error (ENOMEM, name,			      "cannot create shared object descriptor");	  /* We use an opencount of 0 as a sign for the faked entry.  */	  l->l_opencount = 0;	  l->l_reserved = 0;	  l->l_buckets = &dummy_bucket;	  l->l_nbuckets = 1;	  l->l_relocated = 1;	  return l;	}      else	_dl_signal_error (errno, name, "cannot open shared object file");    }  return _dl_map_object_from_fd (name, fd, realname, loader, type);}