Logo Search packages:      
Sourcecode: elfutils version File versions  Download package

ldgeneric.c

/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
   This file is part of Red Hat elfutils.
   Written by Ulrich Drepper <drepper@redhat.com>, 2001.

   Red Hat elfutils is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by the
   Free Software Foundation; version 2 of the License.

   Red Hat elfutils is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with Red Hat elfutils; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.

   Red Hat elfutils is an included package of the Open Invention Network.
   An included package of the Open Invention Network is a package for which
   Open Invention Network licensees cross-license their patents.  No patent
   license is granted, either expressly or impliedly, by designation as an
   included package.  Should you wish to participate in the Open Invention
   Network licensing program, please visit www.openinventionnetwork.com
   <http://www.openinventionnetwork.com>.  */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <gelf.h>
#include <inttypes.h>
#include <libintl.h>
#include <stdbool.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>

#include <system.h>
#include "ld.h"
#include "list.h"


/* Header of .eh_frame_hdr section.  */
struct unw_eh_frame_hdr
{
  unsigned char version;
  unsigned char eh_frame_ptr_enc;
  unsigned char fde_count_enc;
  unsigned char table_enc;
};
#define EH_FRAME_HDR_VERSION 1


/* Prototypes for local functions.  */
static const char **ld_generic_lib_extensions (struct ld_state *)
     __attribute__ ((__const__));
static int ld_generic_file_close (struct usedfiles *fileinfo,
                          struct ld_state *statep);
static int ld_generic_file_process (int fd, struct usedfiles *fileinfo,
                            struct ld_state *statep,
                            struct usedfiles **nextp);
static void ld_generic_generate_sections (struct ld_state *statep);
static void ld_generic_create_sections (struct ld_state *statep);
static int ld_generic_flag_unresolved (struct ld_state *statep);
static int ld_generic_open_outfile (struct ld_state *statep, int machine,
                            int class, int data);
static int ld_generic_create_outfile (struct ld_state *statep);
static void ld_generic_relocate_section (struct ld_state *statep,
                               Elf_Scn *outscn,
                               struct scninfo *firstp,
                               const Elf32_Word *dblindirect);
static int ld_generic_finalize (struct ld_state *statep);
static bool ld_generic_special_section_number_p (struct ld_state *statep,
                                     size_t number);
static bool ld_generic_section_type_p (struct ld_state *statep,
                               XElf_Word type);
static XElf_Xword ld_generic_dynamic_section_flags (struct ld_state *statep);
static void ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn);
static void ld_generic_initialize_pltrel (struct ld_state *statep,
                                Elf_Scn *scn);
static void ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn);
static void ld_generic_finalize_plt (struct ld_state *statep, size_t nsym,
                             size_t nsym_dyn);
static int ld_generic_rel_type (struct ld_state *statep);
static void ld_generic_count_relocations (struct ld_state *statep,
                                struct scninfo *scninfo);
static void ld_generic_create_relocations (struct ld_state *statep,
                                 const Elf32_Word *dblindirect);

static int file_process2 (struct usedfiles *fileinfo);
static void mark_section_used (struct scninfo *scninfo, Elf32_Word shndx,
                         struct scninfo **grpscnp);


/* Map symbol index to struct symbol record.  */
static struct symbol **ndxtosym;

/* String table reference to all symbols in the symbol table.  */
static struct Ebl_Strent **symstrent;


/* Check whether file associated with FD is a DSO.  */
static bool
is_dso_p (int fd)
{
  /* We have to read the 'e_type' field.  It has the same size (16
     bits) in 32- and 64-bit ELF.  */
  XElf_Half e_type;

  return (pread (fd, &e_type, sizeof (e_type), offsetof (XElf_Ehdr, e_type))
        == sizeof (e_type)
        && e_type == ET_DYN);
}


/* Print the complete name of a file, including the archive it is
   contained in.  */
static int
print_file_name (FILE *s, struct usedfiles *fileinfo, int first_level,
             int newline)
{
  int npar = 0;

  if (fileinfo->archive_file != NULL)
    {
      npar = print_file_name (s, fileinfo->archive_file, 0, 0) + 1;
      fputc_unlocked ('(', s);
      fputs_unlocked (fileinfo->rfname, s);

      if (first_level)
      while (npar-- > 0)
        fputc_unlocked (')', s);
    }
  else
    fputs_unlocked (fileinfo->rfname, s);

  if (first_level && newline)
    fputc_unlocked ('\n', s);

  return npar;
}


/* Function to determine whether an object will be dynamically linked.  */
bool
dynamically_linked_p (void)
{
  return (ld_state.file_type == dso_file_type || ld_state.nplt > 0
        || ld_state.ngot > 0);
}


bool
linked_from_dso_p (struct scninfo *scninfo, size_t symidx)
{
  struct usedfiles *file = scninfo->fileinfo;

  /* If this symbol is not undefined in this file it cannot come from
     a DSO.  */
  if (symidx < file->nlocalsymbols)
    return false;

  struct symbol *sym = file->symref[symidx];

  return sym->defined && sym->in_dso;
}


/* Initialize state object.  This callback function is called after the
   parameters are parsed but before any file is searched for.  */
int
ld_prepare_state (const char *emulation)
{
  /* When generating DSO we normally allow undefined symbols.  */
  ld_state.nodefs = true;

  /* To be able to detect problems we add a .comment section entry by
     default.  */
  ld_state.add_ld_comment = true;

  /* XXX We probably should find a better place for this.  The index
     of the first user-defined version is 2.  */
  ld_state.nextveridx = 2;

  /* Pick an not too small number for the initial size of the tables.  */
  ld_symbol_tab_init (&ld_state.symbol_tab, 1027);
  ld_section_tab_init (&ld_state.section_tab, 67);
  ld_version_str_tab_init (&ld_state.version_str_tab, 67);

  /* Initialize the section header string table.  */
  ld_state.shstrtab = ebl_strtabinit (true);
  if (ld_state.shstrtab == NULL)
    error (EXIT_FAILURE, errno, gettext ("cannot create string table"));

  /* Initialize the callbacks.  These are the defaults, the appropriate
     backend can later install its own callbacks.  */
  ld_state.callbacks.lib_extensions = ld_generic_lib_extensions;
  ld_state.callbacks.file_process = ld_generic_file_process;
  ld_state.callbacks.file_close = ld_generic_file_close;
  ld_state.callbacks.generate_sections = ld_generic_generate_sections;
  ld_state.callbacks.create_sections = ld_generic_create_sections;
  ld_state.callbacks.flag_unresolved = ld_generic_flag_unresolved;
  ld_state.callbacks.open_outfile = ld_generic_open_outfile;
  ld_state.callbacks.create_outfile = ld_generic_create_outfile;
  ld_state.callbacks.relocate_section = ld_generic_relocate_section;
  ld_state.callbacks.finalize = ld_generic_finalize;
  ld_state.callbacks.special_section_number_p =
    ld_generic_special_section_number_p;
  ld_state.callbacks.section_type_p = ld_generic_section_type_p;
  ld_state.callbacks.dynamic_section_flags = ld_generic_dynamic_section_flags;
  ld_state.callbacks.initialize_plt = ld_generic_initialize_plt;
  ld_state.callbacks.initialize_pltrel = ld_generic_initialize_pltrel;
  ld_state.callbacks.initialize_got = ld_generic_initialize_got;
  ld_state.callbacks.finalize_plt = ld_generic_finalize_plt;
  ld_state.callbacks.rel_type = ld_generic_rel_type;
  ld_state.callbacks.count_relocations = ld_generic_count_relocations;
  ld_state.callbacks.create_relocations = ld_generic_create_relocations;

#ifndef BASE_ELF_NAME
  /* Find the ld backend library.  Use EBL to determine the name if
     the user hasn't provided one on the command line.  */
  if (emulation == NULL)
    {
      emulation = ebl_backend_name (ld_state.ebl);
      assert (emulation != NULL);
    }
  size_t emulation_len = strlen (emulation);

  /* Construct the file name.  */
  char *fname = (char *) alloca (sizeof "libld_" - 1 + emulation_len
                         + sizeof ".so");
  strcpy (mempcpy (stpcpy (fname, "libld_"), emulation, emulation_len), ".so");

  /* Try loading.  */
  void *h = dlopen (fname, RTLD_LAZY);
  if (h == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot load ld backend library '%s': %s"),
         fname, dlerror ());

  /* Find the initializer.  It must be present.  */
  char *initname = (char *) alloca (emulation_len + sizeof "_ld_init");
  strcpy (mempcpy (initname, emulation, emulation_len), "_ld_init");
  int (*initfct) (struct ld_state *)
    = (int (*) (struct ld_state *)) dlsym (h, initname);

  if (initfct == NULL)
    error (EXIT_FAILURE, 0, gettext ("\
cannot find init function in ld backend library '%s': %s"),
         fname, dlerror ());

  /* Store the handle.  */
  ld_state.ldlib = h;

  /* Call the init function.  */
  return initfct (&ld_state);
#else
# define INIT_FCT_NAME(base) _INIT_FCT_NAME(base)
# define _INIT_FCT_NAME(base) base##_ld_init
  /* Declare and call the initialization function.  */
  extern int INIT_FCT_NAME(BASE_ELF_NAME) (struct ld_state *);
  return INIT_FCT_NAME(BASE_ELF_NAME) (&ld_state);
#endif
}


static int
check_for_duplicate2 (struct usedfiles *newp, struct usedfiles *list)
{
  struct usedfiles *first;
  struct usedfiles *prevp;

  if (list == NULL)
    return 0;

  prevp = list;
  list = first = list->next;
  do
    {
      /* When searching the needed list we might come across entries
       for files which are not yet opened.  Stop then, there is
       nothing more to test.  */
      if (likely (list->status == not_opened))
      break;

      if (unlikely (list->ino == newp->ino)
        && unlikely (list->dev == newp->dev))
      {
        close (newp->fd);
        newp->fd = -1;
        newp->status = closed;
        if (newp->file_type == relocatable_file_type)
          error (0, 0, gettext ("%s listed more than once as input"),
               newp->rfname);

        return 1;
      }
      list = list->next;
    }
  while (likely (list != first));

  return 0;
}


static int
check_for_duplicate (struct usedfiles *newp)
{
  struct stat st;

  if (unlikely (fstat (newp->fd, &st) < 0))
    {
      close (newp->fd);
      return errno;
    }

  newp->dev = st.st_dev;
  newp->ino = st.st_ino;

  return (check_for_duplicate2 (newp, ld_state.relfiles)
        || check_for_duplicate2 (newp, ld_state.dsofiles)
        || check_for_duplicate2 (newp, ld_state.needed));
}


/* Find a file along the path described in the state.  */
static int
open_along_path2 (struct usedfiles *fileinfo, struct pathelement *path)
{
  const char *fname = fileinfo->fname;
  size_t fnamelen = strlen (fname);
  int err = ENOENT;
  struct pathelement *firstp = path;

  if (path == NULL)
    /* Cannot find anything since we have no path.  */
    return ENOENT;

  do
    {
      if (likely (path->exist >= 0))
      {
        /* Create the file name.  */
        char *rfname = NULL;
        size_t dirlen = strlen (path->pname);
        int fd = -1;

        if (fileinfo->file_type == archive_file_type)
          {
            const char **exts = (ld_state.statically
                           ? (const char *[2]) { ".a", NULL }
                           : LIB_EXTENSION (&ld_state));

            /* We have to create the actual file name.  We prepend "lib"
             and add one of the extensions the platform has.  */
            while (*exts != NULL)
            {
              size_t extlen = strlen (*exts);
              rfname = (char *) alloca (dirlen + 5 + fnamelen + extlen);
              memcpy (mempcpy (stpcpy (mempcpy (rfname, path->pname,
                                        dirlen),
                                 "/lib"),
                           fname, fnamelen),
                    *exts, extlen + 1);

              fd = open (rfname, O_RDONLY);
              if (likely (fd != -1) || errno != ENOENT)
                {
                  err = fd == -1 ? errno : 0;
                  break;
                }

              /* Next extension.  */
              ++exts;
            }
          }
        else
          {
            assert (fileinfo->file_type == dso_file_type
                  || fileinfo->file_type == dso_needed_file_type);

            rfname = (char *) alloca (dirlen + 1 + fnamelen + 1);
            memcpy (stpcpy (mempcpy (rfname, path->pname, dirlen), "/"),
                  fname, fnamelen + 1);

            fd = open (rfname, O_RDONLY);
            if (unlikely (fd == -1))
            err = errno;
          }

        if (likely (fd != -1))
          {
            /* We found the file.  This also means the directory
             exists.  */
            fileinfo->fd = fd;
            path->exist = 1;

            /* Check whether we have this file already loaded.  */
            if (unlikely (check_for_duplicate (fileinfo) != 0))
            return EAGAIN;

            /* Make a copy of the name.  */
            fileinfo->rfname = obstack_strdup (&ld_state.smem, rfname);

            if (unlikely (ld_state.trace_files))
            printf (fileinfo->file_type == archive_file_type
                  ? gettext ("%s (for -l%s)\n")
                  : gettext ("%s (for DT_NEEDED %s)\n"),
                  rfname, fname);

            return 0;
          }

        /* The file does not exist.  Maybe the whole directory doesn't.
           Check it unless we know it exists.  */
        if (unlikely (path->exist == 0))
          {
            struct stat st;

            /* Keep only the directory name.  Note that the path
             might be relative.  This doesn't matter here.  We do
             the test in any case even if there is the chance that
             somebody wants to change the programs working
             directory at some point which would make the result
             of this test void.  Since changing the working
             directory is completely wrong we are not taking this
             case into account.  */
            rfname[dirlen] = '\0';
            if (unlikely (stat (rfname, &st) < 0) || ! S_ISDIR (st.st_mode))
            /* The directory does not exist or the named file is no
               directory.  */
            path->exist = -1;
            else
            path->exist = 1;
          }
      }

      /* Next path element.  */
      path = path->next;
    }
  while (likely (err == ENOENT && path != firstp));

  return err;
}


static int
open_along_path (struct usedfiles *fileinfo)
{
  const char *fname = fileinfo->fname;
  int err = ENOENT;

  if (fileinfo->file_type == relocatable_file_type)
    {
      /* Only libraries are searched along the path.  */
      fileinfo->fd = open (fname, O_RDONLY);

      if (likely (fileinfo->fd != -1))
      {
        /* We found the file.  */
        if (unlikely (ld_state.trace_files))
          print_file_name (stdout, fileinfo, 1, 1);

        return check_for_duplicate (fileinfo);
      }

      /* If the name is an absolute path we are done.  */
      err = errno;
    }
  else
    {
      /* If the user specified two parts to the LD_LIBRARY_PATH variable
       try the first part now.  */
      err = open_along_path2 (fileinfo, ld_state.ld_library_path1);

      /* Try the user-specified path next.  */
      if (err == ENOENT)
      err = open_along_path2 (fileinfo,
                        fileinfo->file_type == archive_file_type
                        ? ld_state.paths : ld_state.rpath_link);

      /* Then the second part of the LD_LIBRARY_PATH value.  */
      if (unlikely (err == ENOENT))
      {
        err = open_along_path2 (fileinfo, ld_state.ld_library_path2);

        /* In case we look for a DSO handle now the RUNPATH.  */
        if (err == ENOENT)
          {
            if (fileinfo->file_type == dso_file_type)
            err = open_along_path2 (fileinfo, ld_state.runpath_link);

            /* Finally the path from the default linker script.  */
            if (err == ENOENT)
            err = open_along_path2 (fileinfo, ld_state.default_paths);
          }
      }
    }

  if (unlikely (err != 0)
      && (err != EAGAIN || fileinfo->file_type == relocatable_file_type))
    error (0, err, gettext ("cannot open %s"), fileinfo->fname);

  return err;
}


static void
check_type_and_size (const XElf_Sym *sym, struct usedfiles *fileinfo,
                 struct symbol *oldp)
{
  /* We check the type and size of the symbols.  In both cases the
     information can be missing (size is zero, type is STT_NOTYPE) in
     which case we issue no warnings.  Otherwise everything must
     match.  If the type does not match there is no point in checking
     the size.  */

  if (XELF_ST_TYPE (sym->st_info) != STT_NOTYPE && oldp->type != STT_NOTYPE
      && unlikely (oldp->type != XELF_ST_TYPE (sym->st_info)))
    {
      char buf1[64];
      char buf2[64];

      error (0, 0, gettext ("\
Warning: type of `%s' changed from %s in %s to %s in %s"),
           oldp->name,
           ebl_symbol_type_name (ld_state.ebl, oldp->type,
                           buf1, sizeof (buf1)),
           oldp->file->rfname,
           ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info),
                           buf2, sizeof (buf2)),
           fileinfo->rfname);
    }
  else if (XELF_ST_TYPE (sym->st_info) == STT_OBJECT
         && oldp->size != 0
         && unlikely (oldp->size != sym->st_size))
    error (0, 0, gettext ("\
Warning: size of `%s' changed from %" PRIu64 " in %s to %" PRIu64 " in %s"),
         oldp->name, (uint64_t) oldp->size, oldp->file->rfname,
         (uint64_t) sym->st_size, fileinfo->rfname);
}


static int
check_definition (const XElf_Sym *sym, size_t symidx,
              struct usedfiles *fileinfo, struct symbol *oldp)
{
  int result = 0;
  bool old_in_dso = FILEINFO_EHDR (oldp->file->ehdr).e_type == ET_DYN;
  bool new_in_dso = FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN;
  bool use_new_def = false;

  if (sym->st_shndx != SHN_UNDEF
      && (! oldp->defined
        || (sym->st_shndx != SHN_COMMON && oldp->common && ! new_in_dso)
        || (old_in_dso && ! new_in_dso)))
    {
      /* We found a definition for a previously undefined symbol or a
       real definition for a previous common-only definition or a
       redefinition of a symbol definition in an object file
       previously defined in a DSO.  First perform some tests which
       will show whether the common is really matching the
       definition.  */
      check_type_and_size (sym, fileinfo, oldp);

      /* We leave the next element intact to not interrupt the list
       with the unresolved symbols.  Whoever walks the list will
       have to check the `defined' flag.  But we remember that this
       list element is not unresolved anymore.  */
      if (! oldp->defined)
      {
        /* Remove from the list.  */
        --ld_state.nunresolved;
        if (! oldp->weak)
          --ld_state.nunresolved_nonweak;
        CDBL_LIST_DEL (ld_state.unresolved, oldp);
      }
      else if (oldp->common)
      /* Remove from the list.  */
      CDBL_LIST_DEL (ld_state.common_syms, oldp);

      /* Use the values of the definition from now on.  */
      use_new_def = true;
    }
  else if (sym->st_shndx != SHN_UNDEF
         && unlikely (! oldp->common)
         && oldp->defined
         && sym->st_shndx != SHN_COMMON
         /* Multiple definitions are no fatal errors if the -z muldefs flag
            is used.  We don't warn about the multiple definition unless we
            are told to be verbose.  */
         && (!ld_state.muldefs || verbose)
         && ! old_in_dso && fileinfo->file_type == relocatable_file_type)
    {
      /* We have a double definition.  This is a problem.  */
      char buf[64];
      XElf_Sym_vardef (oldsym);
      struct usedfiles *oldfile;
      const char *scnname;
      Elf32_Word xndx;
      size_t shndx;
      size_t shnum;

      if (elf_getshnum (fileinfo->elf, &shnum) < 0)
      error (EXIT_FAILURE, 0,
             gettext ("cannot determine number of sections: %s"),
             elf_errmsg (-1));

      /* XXX Use only ebl_section_name.  */
      if (sym->st_shndx < SHN_LORESERVE // || sym->st_shndx > SHN_HIRESERVE
        && sym->st_shndx < shnum)
      scnname = elf_strptr (fileinfo->elf,
                        fileinfo->shstrndx,
                        SCNINFO_SHDR (fileinfo->scninfo[sym->st_shndx].shdr).sh_name);
      else
      // XXX extended section
      scnname = ebl_section_name (ld_state.ebl, sym->st_shndx, 0,
                            buf, sizeof (buf), NULL, shnum);

      /* XXX Print source file and line number.  */
      print_file_name (stderr, fileinfo, 1, 0);
      fprintf (stderr,
             gettext ("(%s+%#" PRIx64 "): multiple definition of %s `%s'\n"),
             scnname,
             (uint64_t) sym->st_value,
             ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info),
                             buf, sizeof (buf)),
             oldp->name);

      oldfile = oldp->file;
      xelf_getsymshndx (oldfile->symtabdata, oldfile->xndxdata, oldp->symidx,
                  oldsym, xndx);
      if (oldsym == NULL)
      /* This should never happen since the same call
         succeeded before.  */
      abort ();

      shndx = oldsym->st_shndx;
      if (unlikely (oldsym->st_shndx == SHN_XINDEX))
      shndx = xndx;

      /* XXX Use only ebl_section_name.  */
      if (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)
      scnname = elf_strptr (oldfile->elf,
                        oldfile->shstrndx,
                        SCNINFO_SHDR (oldfile->scninfo[shndx].shdr).sh_name);
      else
      scnname = ebl_section_name (ld_state.ebl, oldsym->st_shndx, shndx, buf,
                            sizeof (buf), NULL, shnum);

      /* XXX Print source file and line number.  */
      print_file_name (stderr, oldfile, 1, 0);
      fprintf (stderr, gettext ("(%s+%#" PRIx64 "): first defined here\n"),
             scnname, (uint64_t) oldsym->st_value);

      if (likely (!ld_state.muldefs))
      result = 1;
    }
  else if (old_in_dso && fileinfo->file_type == relocatable_file_type
         && sym->st_shndx != SHN_UNDEF)
    /* We use the definition from a normal relocatable file over the
       definition in a DSO.  This is what the dynamic linker would
       do, too.  */
    use_new_def = true;
  else if (old_in_dso && !new_in_dso && oldp->defined && !oldp->on_dsolist)
    {
      CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp);
      ++ld_state.nfrom_dso;

      /* If the object is a function we allocate a PLT entry,
       otherwise only a GOT entry.  */
      if (oldp->type == STT_FUNC)
      ++ld_state.nplt;
      else
      ++ld_state.ngot;

      oldp->on_dsolist = 1;
    }
  else if (oldp->common && sym->st_shndx == SHN_COMMON)
    {
      /* The symbol size is the largest of all common definitions.  */
      oldp->size = MAX (oldp->size, sym->st_size);
      /* Similarly for the alignment.  */
      oldp->merge.value = MAX (oldp->merge.value, sym->st_value);
    }

  if (unlikely (use_new_def))
    {
      /* Adjust the symbol record appropriately and remove
       the symbol from the list of symbols which are taken from DSOs.  */
      if (old_in_dso && fileinfo->file_type == relocatable_file_type)
      {
        CDBL_LIST_DEL (ld_state.from_dso, oldp);
        --ld_state.nfrom_dso;

        if (likely (oldp->type == STT_FUNC))
          --ld_state.nplt;
        else
          --ld_state.ngot;

        oldp->on_dsolist = 0;
      }

      /* Use the values of the definition from now on.  */
      oldp->size = sym->st_size;
      oldp->type = XELF_ST_TYPE (sym->st_info);
      oldp->symidx = symidx;
      oldp->scndx = sym->st_shndx;
      //oldp->symscndx = THESYMSCNDX must be passed;
      oldp->file = fileinfo;
      oldp->defined = 1;
      oldp->in_dso = new_in_dso;
      oldp->common = sym->st_shndx == SHN_COMMON;
      if (likely (fileinfo->file_type == relocatable_file_type))
      {
        /* If the definition comes from a DSO we pertain the weak flag
           and it's indicating whether the reference is weak or not.  */
        oldp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK;

        if (sym->st_shndx != SHN_COMMON)
          {
            struct scninfo *ignore;
            mark_section_used (&fileinfo->scninfo[sym->st_shndx],
                         sym->st_shndx, &ignore);
          }
      }

      /* Add to the list of symbols used from DSOs if necessary.  */
      if (new_in_dso && !old_in_dso)
      {
        CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp);
        ++ld_state.nfrom_dso;

        /* If the object is a function we allocate a PLT entry,
           otherwise only a GOT entry.  */
        if (oldp->type == STT_FUNC)
          ++ld_state.nplt;
        else
          ++ld_state.ngot;

        oldp->on_dsolist = 1;
      }
      else if (sym->st_shndx == SHN_COMMON)
      {
        /* Store the alignment.  */
        oldp->merge.value = sym->st_value;

        CDBL_LIST_ADD_REAR (ld_state.common_syms, oldp);
      }
    }

  return result;
}


static struct scninfo *
find_section_group (struct usedfiles *fileinfo, Elf32_Word shndx,
                Elf_Data **datap)
{
  struct scninfo *runp;

  for (runp = fileinfo->groups; runp != NULL; runp = runp->next)
    if (!runp->used)
      {
      Elf32_Word *grpref;
      size_t cnt;
      Elf_Data *data;

      data = elf_getdata (runp->scn, NULL);
      if (data == NULL)
        error (EXIT_FAILURE, 0,
             gettext ("%s: cannot get section group data: %s"),
             fileinfo->fname, elf_errmsg (-1));

      /* There cannot be another data block.  */
      assert (elf_getdata (runp->scn, data) == NULL);

      grpref = (Elf32_Word *) data->d_buf;
      cnt = data->d_size / sizeof (Elf32_Word);
      /* Note that we stop after looking at index 1 since index 0
         contains the flags for the section group.  */
      while (cnt > 1)
        if (grpref[--cnt] == shndx)
          {
            *datap = data;
            return runp;
          }
      }

  /* If we come here no section group contained the given section
     despite the SHF_GROUP flag.  This is an error in the input
     file.  */
  error (EXIT_FAILURE, 0, gettext ("\
%s: section '%s' with group flag set does not belong to any group"),
       fileinfo->fname,
       elf_strptr (fileinfo->elf, fileinfo->shstrndx,
                 SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_name));
  return NULL;
}


/* Mark all sections which belong to the same group as section SHNDX
   as used.  */
static void
mark_section_group (struct usedfiles *fileinfo, Elf32_Word shndx,
                struct scninfo **grpscnp)
{
  /* First locate the section group.  There can be several (many) of
     them.  */
  size_t cnt;
  Elf32_Word *grpref;
  Elf_Data *data;
  struct scninfo *grpscn = find_section_group (fileinfo, shndx, &data);
  *grpscnp = grpscn;

  /* Mark all the sections as used.

     XXX Two possible problems here:

     - the gABI says "The section must be referenced by a section of type
       SHT_GROUP".  I hope everybody reads this as "exactly one section".

     - section groups are also useful to mark the debugging section which
       belongs to a text section.  Unconditionally adding debugging sections
       is therefore probably not what is wanted if stripping is required.  */

  /* Mark the section group as handled.  */
  grpscn->used = true;

  grpref = (Elf32_Word *) data->d_buf;
  cnt = data->d_size / sizeof (Elf32_Word);
  while (cnt > 1)
    {
      Elf32_Word idx = grpref[--cnt];
      XElf_Shdr *shdr = &SCNINFO_SHDR (fileinfo->scninfo[idx].shdr);

      if (fileinfo->scninfo[idx].grpid != 0)
      error (EXIT_FAILURE, 0, gettext ("\
%s: section [%2d] '%s' is in more than one section group"),
             fileinfo->fname, (int) idx,
             elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name));

      fileinfo->scninfo[idx].grpid = grpscn->grpid;

      if (ld_state.strip == strip_none
        /* If we are stripping, remove debug sections.  */
        || (!ebl_debugscn_p (ld_state.ebl,
                         elf_strptr (fileinfo->elf, fileinfo->shstrndx,
                                 shdr->sh_name))
            /* And the relocation sections for the debug sections.  */
            && ((shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
              || !ebl_debugscn_p (ld_state.ebl,
                              elf_strptr (fileinfo->elf,
                                      fileinfo->shstrndx,
                                      SCNINFO_SHDR (fileinfo->scninfo[shdr->sh_info].shdr).sh_name)))))
      {
        struct scninfo *ignore;

        mark_section_used (&fileinfo->scninfo[idx], idx, &ignore);
      }
    }
}


static void
mark_section_used (struct scninfo *scninfo, Elf32_Word shndx,
               struct scninfo **grpscnp)
{
  if (likely (scninfo->used))
    /* Nothing to be done.  */
    return;

  /* We need this section.  */
  scninfo->used = true;

  /* Make sure the section header has been read from the file.  */
  XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr);
#if NATIVE_ELF
  if (unlikely (scninfo->shdr == NULL))
#else
  if (unlikely (scninfo->shdr.sh_type == SHT_NULL))
#endif
    {
#if NATIVE_ELF != 0
      shdr = xelf_getshdr (scninfo->scn, scninfo->shdr);
#else
      xelf_getshdr_copy (scninfo->scn, shdr, scninfo->shdr);
#endif
      if (unlikely (shdr == NULL))
      /* Something is very wrong.  The calling code will notice it
         soon and print a message.  */
      return;
    }

  /* Handle section linked by 'sh_link'.  */
  if (unlikely (shdr->sh_link != 0))
    {
      struct scninfo *ignore;
      mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_link],
                   shdr->sh_link, &ignore);
    }

  /* Handle section linked by 'sh_info'.  */
  if (unlikely (shdr->sh_info != 0) && (shdr->sh_flags & SHF_INFO_LINK))
    {
      struct scninfo *ignore;
      mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_info],
                   shdr->sh_info, &ignore);
    }

  if (unlikely (shdr->sh_flags & SHF_GROUP) && ld_state.gc_sections)
    /* Find the section group which contains this section.  */
    mark_section_group (scninfo->fileinfo, shndx, grpscnp);
}


/* We collect all sections in a hashing table.  All sections with the
   same name are collected in a list.  Note that we do not determine
   which sections are finally collected in the same output section
   here.  This would be terribly inefficient.  It will be done later.  */
static void
add_section (struct usedfiles *fileinfo, struct scninfo *scninfo)
{
  struct scnhead *queued;
  struct scnhead search;
  unsigned long int hval;
  XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr);
  struct scninfo *grpscn = NULL;
  Elf_Data *grpscndata = NULL;

  /* See whether we can determine right away whether we need this
     section in the output.

     XXX I assume here that --gc-sections only affects extraction
     from an archive.  If it also affects objects files given on
     the command line then somebody must explain to me how the
     dependency analysis should work.  Should the entry point be
     the root?  What if it is a numeric value?  */
  if (!scninfo->used
      && (ld_state.strip == strip_none
        || (shdr->sh_flags & SHF_ALLOC) != 0
        || shdr->sh_type == SHT_NOTE
        || (shdr->sh_type == SHT_PROGBITS
            && strcmp (elf_strptr (fileinfo->elf,
                             fileinfo->shstrndx,
                             shdr->sh_name), ".comment") == 0))
      && (fileinfo->status != in_archive || !ld_state.gc_sections))
    /* Mark as used and handle reference recursively if necessary.  */
    mark_section_used (scninfo, elf_ndxscn (scninfo->scn), &grpscn);

  if ((shdr->sh_flags & SHF_GROUP) && grpscn == NULL)
    /* Determine the symbol which name constitutes the signature
       for the section group.  */
    grpscn = find_section_group (fileinfo, elf_ndxscn (scninfo->scn),
                         &grpscndata);
  assert (grpscn == NULL || grpscn->symbols->name != NULL);

  /* Determine the section name.  */
  search.name = elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name);
  search.type = shdr->sh_type;
  search.flags = shdr->sh_flags;
  search.entsize = shdr->sh_entsize;
  search.grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL;
  search.kind = scn_normal;
  hval = elf_hash (search.name);

  /* Find already queued sections.  */
  queued = ld_section_tab_find (&ld_state.section_tab, hval, &search);
  if (queued != NULL)
    {
      bool is_comdat = false;

      /* If this section is part of a COMDAT section group we simply
       ignore it since we already have a copy.  */
      if (unlikely (shdr->sh_flags & SHF_GROUP))
      {
        /* Get the data of the section group section.  */
        if (grpscndata == NULL)
          {
            grpscndata = elf_getdata (grpscn->scn, NULL);
            assert (grpscndata != NULL);
          }

        /* XXX Possibly unaligned memory access.  */
        if ((((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT) != 0)
          {
            /* We have to compare the group signatures.  There might
             be sections with the same name but belonging to
             groups with different signatures.  This means we have
             to compare the new group signature with all those
             already collected.  There might also be some
             non-group sections in the mix.  */
            struct scninfo *runp = queued->last;
            do
            {
              if (SCNINFO_SHDR (runp->shdr).sh_flags & SHF_GROUP)
                {
                  struct scninfo *grpscn2
                  = find_section_group (runp->fileinfo,
                                    elf_ndxscn (runp->scn),
                                    &grpscndata);

                  if (strcmp (grpscn->symbols->name,
                          grpscn2->symbols->name) == 0)
                  {
                    scninfo->unused_comdat = is_comdat = true;
                    break;
                  }
                }

              runp = runp->next;
            }
            while (runp != queued->last);
          }
      }

      if (!is_comdat)
      {
        /* No COMDAT section, we use the data.  */
        scninfo->next = queued->last->next;
        queued->last = queued->last->next = scninfo;

        queued->flags = ebl_sh_flags_combine (ld_state.ebl, queued->flags,
                                    shdr->sh_flags);
        queued->align = MAX (queued->align, shdr->sh_addralign);
      }
    }
  else
    {
      /* We do not use obstacks here since the memory might be
       deallocated.  */
      queued = (struct scnhead *) xcalloc (sizeof (struct scnhead), 1);
      queued->kind = scn_normal;
      queued->name = search.name;
      queued->type = shdr->sh_type;
      queued->flags = shdr->sh_flags;
      queued->align = shdr->sh_addralign;
      queued->entsize = shdr->sh_entsize;
      queued->grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL;
      queued->segment_nr = ~0;
      queued->last = scninfo->next = scninfo;

      /* Add to the hash table and possibly overwrite existing value.  */
      ld_section_tab_insert (&ld_state.section_tab, hval, queued);
    }
}


static int
add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
{
  size_t scncnt;
  size_t cnt;
  Elf_Data *symtabdata = NULL;
  Elf_Data *xndxdata = NULL;
  Elf_Data *versymdata = NULL;
  Elf_Data *verdefdata = NULL;
  Elf_Data *verneeddata = NULL;
  size_t symstridx = 0;
  size_t nsymbols = 0;
  size_t nlocalsymbols = 0;
  bool has_merge_sections = false;
  /* Unless we have different information we assume the code needs
     an executable stack.  */
  enum execstack execstack = execstack_true;

  /* Prerequisites.  */
  assert (fileinfo->elf != NULL);

  /* Allocate memory for the sections.  */
  if (unlikely (elf_getshnum (fileinfo->elf, &scncnt) < 0))
    error (EXIT_FAILURE, 0,
         gettext ("cannot determine number of sections: %s"),
         elf_errmsg (-1));

  fileinfo->scninfo = (struct scninfo *)
    obstack_calloc (&ld_state.smem, scncnt * sizeof (struct scninfo));

  /* Read all the section headers and find the symbol table.  Note
     that we don't skip the section with index zero.  Even though the
     section itself is always empty the section header contains
     informaton for the case when the section index for the section
     header string table is too large to fit in the ELF header.  */
  for (cnt = 0; cnt < scncnt; ++cnt)
    {
      /* Store the handle for the section.  */
      fileinfo->scninfo[cnt].scn = elf_getscn (fileinfo->elf, cnt);

      /* Get the ELF section header and data.  */
      XElf_Shdr *shdr;
#if NATIVE_ELF != 0
      if (fileinfo->scninfo[cnt].shdr == NULL)
#else
      if (fileinfo->scninfo[cnt].shdr.sh_type == SHT_NULL)
#endif
      {
#if NATIVE_ELF != 0
        shdr = xelf_getshdr (fileinfo->scninfo[cnt].scn,
                         fileinfo->scninfo[cnt].shdr);
#else
        xelf_getshdr_copy (fileinfo->scninfo[cnt].scn, shdr,
                       fileinfo->scninfo[cnt].shdr);
#endif
        if (shdr == NULL)
          {
            /* This should never happen.  */
            fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                   fileinfo->rfname, __FILE__, __LINE__);
            return 1;
          }
      }
      else
      shdr = &SCNINFO_SHDR (fileinfo->scninfo[cnt].shdr);

      Elf_Data *data = elf_getdata (fileinfo->scninfo[cnt].scn, NULL);

      /* Check whether this section is marked as merge-able.  */
      has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0;

      /* Get the ELF section header and data.  */
      /* Make the file structure available.  */
      fileinfo->scninfo[cnt].fileinfo = fileinfo;

      if (unlikely (shdr->sh_type == SHT_SYMTAB)
        || unlikely (shdr->sh_type == SHT_DYNSYM))
      {
        if (shdr->sh_type == SHT_SYMTAB)
          {
            assert (fileinfo->symtabdata == NULL);
            fileinfo->symtabdata = data;
            fileinfo->nsymtab = shdr->sh_size / shdr->sh_entsize;
            fileinfo->nlocalsymbols = shdr->sh_info;
            fileinfo->symstridx = shdr->sh_link;
          }
        else
          {
            assert (fileinfo->dynsymtabdata == NULL);
            fileinfo->dynsymtabdata = data;
            fileinfo->ndynsymtab = shdr->sh_size / shdr->sh_entsize;
            fileinfo->dynsymstridx = shdr->sh_link;
          }

        /* If we are looking for the normal symbol table we just
           found it.  */
        if (secttype == shdr->sh_type)
          {
            assert (symtabdata == NULL);
            symtabdata = data;
            symstridx = shdr->sh_link;
            nsymbols = shdr->sh_size / shdr->sh_entsize;
            nlocalsymbols = shdr->sh_info;
          }
      }
      else if (unlikely (shdr->sh_type == SHT_SYMTAB_SHNDX))
      {
        assert (xndxdata == NULL);
        fileinfo->xndxdata = xndxdata = data;
      }
      else if (unlikely (shdr->sh_type == SHT_GNU_versym))
      {
        assert (versymdata == 0);
        fileinfo->versymdata = versymdata = data;
      }
      else if (unlikely (shdr->sh_type == SHT_GNU_verdef))
      {
        size_t nversions;

        assert (verdefdata == 0);
        fileinfo->verdefdata = verdefdata = data;

        /* Allocate the arrays flagging the use of the version and
           to track of allocated names.  */
        fileinfo->nverdef = nversions = shdr->sh_info;
        /* We have NVERSIONS + 1 because the indeces used to access the
           sectino start with one; zero represents local binding.  */
        fileinfo->verdefused = (XElf_Versym *)
          obstack_calloc (&ld_state.smem,
                      sizeof (XElf_Versym) * (nversions + 1));
        fileinfo->verdefent = (struct Ebl_Strent **)
          obstack_alloc (&ld_state.smem,
                     sizeof (struct Ebl_Strent *) * (nversions + 1));
      }
      else if (unlikely (shdr->sh_type == SHT_GNU_verneed))
      {
        assert (verneeddata == 0);
        fileinfo->verneeddata = verneeddata = data;
      }
      else if (unlikely (shdr->sh_type == SHT_DYNAMIC))
      {
        assert (fileinfo->dynscn == NULL);
        fileinfo->dynscn = fileinfo->scninfo[cnt].scn;
      }
      else if (unlikely (shdr->sh_type == SHT_GROUP))
      {
        Elf_Scn *symscn;
        XElf_Shdr_vardef (symshdr);
        Elf_Data *symdata;

        if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL)
          error (EXIT_FAILURE, 0, gettext ("\
%s: only files of type ET_REL might contain section groups"),
               fileinfo->fname);

        fileinfo->scninfo[cnt].next = fileinfo->groups;
        fileinfo->scninfo[cnt].grpid = cnt;
        fileinfo->groups = &fileinfo->scninfo[cnt];

        /* Determine the signature.  We create a symbol record for
           it.  Only the name element is important.  */
        fileinfo->scninfo[cnt].symbols = (struct symbol *)
          obstack_calloc (&ld_state.smem, sizeof (struct symbol));

        symscn = elf_getscn (fileinfo->elf, shdr->sh_link);
        xelf_getshdr (symscn, symshdr);
        symdata = elf_getdata (symscn, NULL);
        if (symshdr != NULL)
          {
            XElf_Sym_vardef (sym);

            /* We don't need the section index and therefore we don't
             have to use 'xelf_getsymshndx'.  */
            xelf_getsym (symdata, shdr->sh_info, sym);
            if (sym != NULL)
            {
              struct symbol *symbol = fileinfo->scninfo[cnt].symbols;

              symbol->name = elf_strptr (fileinfo->elf, symshdr->sh_link,
                                   sym->st_name);
              symbol->symidx = shdr->sh_info;
              symbol->file = fileinfo;
            }
          }
        if (fileinfo->scninfo[cnt].symbols->name == NULL)
          error (EXIT_FAILURE, 0, gettext ("\
%s: cannot determine signature of section group [%2zd] '%s': %s"),
               fileinfo->fname,
               elf_ndxscn (fileinfo->scninfo[cnt].scn),
               elf_strptr (fileinfo->elf, fileinfo->shstrndx,
                         shdr->sh_name),
               elf_errmsg (-1));

        /* The 'used' flag is used to indicate when the information
           in the section group is used to mark all other sections
           as used.  So it must not be true yet.  */
        assert (fileinfo->scninfo[cnt].used == false);
      }
      else if (! SECTION_TYPE_P (&ld_state, shdr->sh_type)
             && unlikely ((shdr->sh_flags & SHF_OS_NONCONFORMING) != 0))
      /* According to the gABI it is a fatal error if the file contains
         a section with unknown type and the SHF_OS_NONCONFORMING flag
         set.  */
      error (EXIT_FAILURE, 0,
             gettext ("%s: section '%s' has unknown type: %d"),
             fileinfo->fname,
             elf_strptr (fileinfo->elf, fileinfo->shstrndx,
                     shdr->sh_name),
             (int) shdr->sh_type);
      /* We don't have to add a few section types here.  These will be
       generated from scratch for the new output file.  We also
       don't add the sections of DSOs here since these sections are
       not used in the resulting object file.  */
      else if (likely (fileinfo->file_type == relocatable_file_type)
             && likely (cnt > 0)
             && likely (shdr->sh_type == SHT_PROGBITS
                    || shdr->sh_type == SHT_RELA
                    || shdr->sh_type == SHT_REL
                    || shdr->sh_type == SHT_NOTE
                    || shdr->sh_type == SHT_NOBITS
                    || shdr->sh_type == SHT_INIT_ARRAY
                    || shdr->sh_type == SHT_FINI_ARRAY
                    || shdr->sh_type == SHT_PREINIT_ARRAY))
      {
        /* Check whether the check needs to be executable.  */
        if (shdr->sh_type == SHT_PROGBITS
            && (shdr->sh_flags & SHF_EXECINSTR) == 0
            && strcmp (elf_strptr (fileinfo->elf, fileinfo->shstrndx,
                             shdr->sh_name),
                   ".note.GNU-stack") == 0)
          execstack = execstack_false;

        add_section (fileinfo, &fileinfo->scninfo[cnt]);
      }
    }

  /* Now we know more about the requirements for an executable stack
     of the result.  */
  if (fileinfo->file_type == relocatable_file_type
      && execstack == execstack_true
      && ld_state.execstack != execstack_false_force)
    ld_state.execstack = execstack_true;

  /* Handle the symbols.  Record defined and undefined symbols in the
     hash table.  In theory there can be a file without any symbol
     table.  */
  if (likely (symtabdata != NULL))
    {
      /* In case this file contains merge-able sections we have to
       locate the symbols which are in these sections.  */
      fileinfo->has_merge_sections = has_merge_sections;
      if (likely (has_merge_sections))
      {
        fileinfo->symref = (struct symbol **)
          obstack_calloc (&ld_state.smem,
                      nsymbols * sizeof (struct symbol *));

        /* Only handle the local symbols here.  */
        for (cnt = 0; cnt < nlocalsymbols; ++cnt)
          {
            Elf32_Word shndx;
            XElf_Sym_vardef (sym);

            xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx);
            if (sym == NULL)
            {
              /* This should never happen.  */
              fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                     fileinfo->rfname, __FILE__, __LINE__);
              return 1;
            }

            if (likely (shndx != SHN_XINDEX))
            shndx = sym->st_shndx;
            else if (unlikely (shndx == 0))
            {
              fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                     fileinfo->rfname, __FILE__, __LINE__);
              return 1;
            }

            if (XELF_ST_TYPE (sym->st_info) != STT_SECTION
              && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)
              && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags
                  & SHF_MERGE))
            {
              /* Create a symbol record for this symbol and add it
                 to the list for this section.  */
              struct symbol *newp;

              newp = (struct symbol *)
                obstack_calloc (&ld_state.smem, sizeof (struct symbol));

              newp->symidx = cnt;
              newp->scndx = shndx;
              newp->file = fileinfo;
              fileinfo->symref[cnt] = newp;

              if (fileinfo->scninfo[shndx].symbols == NULL)
                fileinfo->scninfo[shndx].symbols = newp->next_in_scn
                  = newp;
              else
                {
                  newp->next_in_scn
                  = fileinfo->scninfo[shndx].symbols->next_in_scn;
                  fileinfo->scninfo[shndx].symbols
                  = fileinfo->scninfo[shndx].symbols->next_in_scn = newp;
                }
            }
          }
      }
      else
      /* Create array with pointers to the symbol definitions.  Note
         that we only allocate memory for the non-local symbols
         since we have no merge-able sections.  But we store the
         pointer as if it was for the whole symbol table.  This
         saves some memory.  */
      fileinfo->symref = (struct symbol **)
        obstack_calloc (&ld_state.smem, ((nsymbols - nlocalsymbols)
                                 * sizeof (struct symbol *)))
        - nlocalsymbols;

      /* Don't handle local symbols here.  It's either not necessary
       at all or has already happened.  */
      for (cnt = nlocalsymbols; cnt < nsymbols; ++cnt)
      {
        XElf_Sym_vardef (sym);
        Elf32_Word shndx;
        xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx);

        if (sym == NULL)
          {
            /* This should never happen.  */
            fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                   fileinfo->rfname, __FILE__, __LINE__);
            return 1;
          }

        if (likely (shndx != SHN_XINDEX))
          shndx = sym->st_shndx;
        else if (unlikely (shndx == 0))
          {
            fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                   fileinfo->rfname, __FILE__, __LINE__);
            return 1;
          }

        /* We ignore ABS symbols from DSOs.  */
        // XXX Is this correct?
        if (unlikely (shndx == SHN_ABS) && secttype == SHT_DYNSYM)
          continue;

        if ((shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)
            && fileinfo->scninfo[shndx].unused_comdat)
          /* The symbol is not used.  */
          continue;

        /* If the DSO uses symbols determine whether this is the default
           version.  Otherwise we'll ignore the symbol.  */
        if (versymdata != NULL)
          {
            XElf_Versym versym;

            if (xelf_getversym_copy (versymdata, cnt, versym) == NULL)
            /* XXX Should we handle faulty input files more graceful?  */
            assert (! "xelf_getversym failed");

            if ((versym & 0x8000) != 0)
            /* Ignore the symbol, it's not the default version.  */
            continue;
          }

        /* See whether we know anything about this symbol.  */
        struct symbol search;
        search.name = elf_strptr (fileinfo->elf, symstridx, sym->st_name);
        unsigned long int hval = elf_hash (search.name);

        /* We ignore the symbols the linker generates.  This are
           _GLOBAL_OFFSET_TABLE_, _DYNAMIC.  */
        // XXX This loop is hot and the following tests hardly ever match.
        // XXX Maybe move the tests somewhere they are executed less often.
        if (((unlikely (hval == 165832675ul)
            && strcmp (search.name, "_DYNAMIC") == 0)
             || (unlikely (hval == 102264335ul)
               && strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") == 0))
            && sym->st_shndx != SHN_UNDEF
            /* If somebody defines such a variable in a relocatable we
             don't ignore it.  Let the user get what s/he deserves.  */
            && fileinfo->file_type != relocatable_file_type)
          continue;

        struct symbol *oldp = ld_symbol_tab_find (&ld_state.symbol_tab,
                                        hval, &search);
        struct symbol *newp;
        if (likely (oldp == NULL))
          {
            /* No symbol of this name known.  Add it.  */
            newp = (struct symbol *) obstack_alloc (&ld_state.smem,
                                          sizeof (*newp));
            newp->name = search.name;
            newp->size = sym->st_size;
            newp->type = XELF_ST_TYPE (sym->st_info);
            newp->symidx = cnt;
            newp->outsymidx = 0;
            newp->outdynsymidx = 0;
            newp->scndx = shndx;
            newp->file = fileinfo;
            newp->defined = newp->scndx != SHN_UNDEF;
            newp->common = newp->scndx == SHN_COMMON;
            newp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK;
            newp->added = 0;
            newp->merged = 0;
            newp->local = 0;
            newp->hidden = 0;
            newp->need_copy = 0;
            newp->on_dsolist = 0;
            newp->in_dso = secttype == SHT_DYNSYM;
            newp->next_in_scn = NULL;
#ifndef NDEBUG
            newp->next = NULL;
            newp->previous = NULL;
#endif

            if (newp->scndx == SHN_UNDEF)
            {
              CDBL_LIST_ADD_REAR (ld_state.unresolved, newp);
              ++ld_state.nunresolved;
              if (! newp->weak)
                ++ld_state.nunresolved_nonweak;
            }
            else if (newp->scndx == SHN_COMMON)
            {
              /* Store the alignment requirement.  */
              newp->merge.value = sym->st_value;

              CDBL_LIST_ADD_REAR (ld_state.common_syms, newp);
            }

            /* Insert the new symbol.  */
            if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab,
                                      hval, newp) != 0))
            /* This cannot happen.  */
            abort ();

            fileinfo->symref[cnt] = newp;

            /* We have a few special symbols to recognize.  The symbols
             _init and _fini are the initialization and finalization
             functions respectively.  They have to be made known in
             the dynamic section and therefore we have to find out
             now whether these functions exist or not.  */
            if (hval == 6685956 && strcmp (newp->name, "_init") == 0)
            ld_state.init_symbol = newp;
            else if (hval == 6672457 && strcmp (newp->name, "_fini") == 0)
            ld_state.fini_symbol = newp;
          }
        else if (unlikely (check_definition (sym, cnt, fileinfo, oldp) != 0))
          /* A fatal error (multiple definition of a symbol)
             occurred, no need to continue.  */
          return 1;
        else
          /* Use the previously allocated symbol record.  It has
             been updated in check_definition(), if necessary.  */
          newp = fileinfo->symref[cnt] = oldp;

        /* Mark the section the symbol we need comes from as used.  */
        if (shndx != SHN_UNDEF
            && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE))
          {
            struct scninfo *ignore;

#ifndef NDEBUG
            size_t shnum;
            assert (elf_getshnum (fileinfo->elf, &shnum) == 0);
            assert (shndx < shnum);
#endif

            /* Mark section (and all dependencies) as used.  */
            mark_section_used (&fileinfo->scninfo[shndx], shndx, &ignore);

            /* Check whether the section is merge-able.  In this case we
             have to record the symbol.  */
            if (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags
              & SHF_MERGE)
            {
              if (fileinfo->scninfo[shndx].symbols == NULL)
                fileinfo->scninfo[shndx].symbols = newp->next_in_scn
                  = newp;
              else
                {
                  newp->next_in_scn
                  = fileinfo->scninfo[shndx].symbols->next_in_scn;
                  fileinfo->scninfo[shndx].symbols
                  = fileinfo->scninfo[shndx].symbols->next_in_scn = newp;
                }
            }
          }
      }

      /* This file is used.  */
      if (likely (fileinfo->file_type == relocatable_file_type))
      {
        if (unlikely (ld_state.relfiles == NULL))
          ld_state.relfiles = fileinfo->next = fileinfo;
        else
          {
            fileinfo->next = ld_state.relfiles->next;
            ld_state.relfiles = ld_state.relfiles->next = fileinfo;
          }

        /* Update some summary information in the state structure.  */
        ld_state.nsymtab += fileinfo->nsymtab;
        ld_state.nlocalsymbols += fileinfo->nlocalsymbols;
      }
      else if (likely (fileinfo->file_type == dso_file_type))
      {
        CSNGL_LIST_ADD_REAR (ld_state.dsofiles, fileinfo);
        ++ld_state.ndsofiles;

        if (fileinfo->lazyload)
          /* We have to create another dynamic section entry for the
             DT_POSFLAG_1 entry.

             XXX Once more functionality than the lazyloading flag
             are suppported the test must be extended.  */
          ++ld_state.ndsofiles;
      }
    }

  return 0;
}


int
ld_handle_filename_list (struct filename_list *fnames)
{
  struct filename_list *runp;
  int res = 0;

  for (runp = fnames; runp != NULL; runp = runp->next)
    {
      struct usedfiles *curp;

      /* Create a record for the new file.  */
      curp = runp->real = ld_new_inputfile (runp->name, relocatable_file_type);

      /* Set flags for group handling.  */
      curp->group_start = runp->group_start;
      curp->group_end = runp->group_end;

      /* Set as-needed flag from the file, not the command line.  */
      curp->as_needed = runp->as_needed;

      /* Read the file and everything else which comes up, including
       handling groups.  */
      do
      res |= FILE_PROCESS (-1, curp, &ld_state, &curp);
      while (curp != NULL);
    }

  /* Free the list.  */
  while (fnames != NULL)
    {
      runp = fnames;
      fnames = fnames->next;
      free (runp);
    }

  return res;
}


/* Handle opening of the given file with ELF descriptor.  */
static int
open_elf (struct usedfiles *fileinfo, Elf *elf)
{
  int res = 0;

  if (elf == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot get descriptor for ELF file (%s:%d): %s\n"),
         __FILE__, __LINE__, elf_errmsg (-1));

  if (unlikely (elf_kind (elf) == ELF_K_NONE))
    {
      struct filename_list *fnames;

      /* We don't have to look at this file again.  */
      fileinfo->status = closed;

      /* Let's see whether this is a linker script.  */
      if (fileinfo->fd != -1)
      /* Create a stream from the file handle we know.  */
      ldin = fdopen (fileinfo->fd, "r");
      else
      {
        /* Get the memory for the archive member.  */
        char *content;
        size_t contentsize;

        /* Get the content of the file.  */
        content = elf_rawfile (elf, &contentsize);
        if (content == NULL)
          {
            fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                   fileinfo->rfname, __FILE__, __LINE__);
            return 1;
          }

        /* The content of the file is available in memory.  Read the
           memory region as a stream.  */
        ldin = fmemopen (content, contentsize, "r");
      }

      /* No need for locking.  */
      __fsetlocking (ldin, FSETLOCKING_BYCALLER);

      if (ldin == NULL)
      error (EXIT_FAILURE, errno, gettext ("cannot open '%s'"),
             fileinfo->rfname);

      /* Parse the file.  If it is a linker script no problems will be
       reported.  */
      ld_state.srcfiles = NULL;
      ldlineno = 1;
      ld_scan_version_script = 0;
      ldin_fname = fileinfo->rfname;
      res = ldparse ();

      fclose (ldin);
      if (fileinfo->fd != -1 && !fileinfo->fd_passed)
      {
        /* We won't need the file descriptor again.  */
        close (fileinfo->fd);
        fileinfo->fd = -1;
      }

      elf_end (elf);

      if (unlikely (res != 0))
      /* Something went wrong during parsing.  */
      return 1;

      /* This is no ELF file.  */
      fileinfo->elf = NULL;

      /* Now we have to handle eventual INPUT and GROUP statements in
       the script.  Read the files mentioned.  */
      fnames = ld_state.srcfiles;
      if (fnames != NULL)
      {
        struct filename_list *oldp;

        /* Convert the list into a normal single-linked list.  */
        oldp = fnames;
        fnames = fnames->next;
        oldp->next = NULL;

        /* Remove the list from the state structure.  */
        ld_state.srcfiles = NULL;

        if (unlikely (ld_handle_filename_list (fnames) != 0))
          return 1;
      }

      return 0;
    }

  /* Store the file info.  */
  fileinfo->elf = elf;

  /* The file is ready for action.  */
  fileinfo->status = opened;

  return 0;
}


static int
add_whole_archive (struct usedfiles *fileinfo)
{
  Elf *arelf;
  Elf_Cmd cmd = ELF_C_READ_MMAP_PRIVATE;
  int res = 0;

  while ((arelf = elf_begin (fileinfo->fd, cmd, fileinfo->elf)) != NULL)
    {
      Elf_Arhdr *arhdr = elf_getarhdr (arelf);
      struct usedfiles *newp;

      if (arhdr == NULL)
      abort ();

      /* Just to be sure; since these are no files in the archive
       these names should never be returned.  */
      assert (strcmp (arhdr->ar_name, "/") != 0);
      assert (strcmp (arhdr->ar_name, "//") != 0);

      newp = ld_new_inputfile (arhdr->ar_name, relocatable_file_type);
      newp->archive_file = fileinfo;

      if (unlikely (ld_state.trace_files))
      print_file_name (stdout, newp, 1, 1);

      /* This shows that this file is contained in an archive.  */
      newp->fd = -1;
      /* Store the ELF descriptor.  */
      newp->elf = arelf;
      /* Show that we are open for business.  */
      newp->status = opened;

      /* Proces the file, add all the symbols etc.  */
      res = file_process2 (newp);
      if (unlikely (res != 0))
          break;

      /* Advance to the next archive element.  */
      cmd = elf_next (arelf);
    }

  return res;
}


static int
extract_from_archive (struct usedfiles *fileinfo)
{
  static int archive_seq;
  int res = 0;

  /* This is an archive we are not using completely.  Give it a
     unique number.  */
  fileinfo->archive_seq = ++archive_seq;

  /* If there are no unresolved symbols don't do anything.  */
  if ((likely (ld_state.extract_rule == defaultextract)
       && ld_state.nunresolved_nonweak == 0)
      || (unlikely (ld_state.extract_rule == weakextract)
        && ld_state.nunresolved == 0))
    return 0;

  Elf_Arsym *syms;
  size_t nsyms;

  /* Get all the symbols.  */
  syms = elf_getarsym (fileinfo->elf, &nsyms);
  if (syms == NULL)
    {
    cannot_read_archive:
      error (0, 0, gettext ("cannot read archive `%s': %s"),
           fileinfo->rfname, elf_errmsg (-1));

      /* We cannot use this archive anymore.  */
      fileinfo->status = closed;

      return 1;
    }

  /* Now add all the symbols to the hash table.  Note that there
     can potentially be duplicate definitions.  We'll always use
     the first definition.  */
  // XXX Is this a compatible behavior?
  bool any_used;
  int nround = 0;
  do
    {
      any_used = false;

      size_t cnt;
      for (cnt = 0; cnt < nsyms; ++cnt)
      {
        struct symbol search = { .name = syms[cnt].as_name };
        struct symbol *sym = ld_symbol_tab_find (&ld_state.symbol_tab,
                                       syms[cnt].as_hash, &search);
        if (sym != NULL && ! sym->defined)
          {
            /* The symbol is referenced and not defined.  */
            Elf *arelf;
            Elf_Arhdr *arhdr;
            struct usedfiles *newp;

            /* Find the archive member for this symbol.  */
            if (unlikely (elf_rand (fileinfo->elf, syms[cnt].as_off)
                      != syms[cnt].as_off))
            goto cannot_read_archive;

            /* Note: no test of a failing 'elf_begin' call.  That's fine
             since 'elf'getarhdr' will report the problem.  */
            arelf = elf_begin (fileinfo->fd, ELF_C_READ_MMAP_PRIVATE,
                         fileinfo->elf);
            arhdr = elf_getarhdr (arelf);
            if (arhdr == NULL)
            goto cannot_read_archive;

            /* We have all the information and an ELF handle for the
             archive member.  Create the normal data structure for
             a file now.  */
            newp = ld_new_inputfile (obstack_strdup (&ld_state.smem,
                                           arhdr->ar_name),
                               relocatable_file_type);
            newp->archive_file = fileinfo;

            if (unlikely (ld_state.trace_files))
            print_file_name (stdout, newp, 1, 1);

            /* This shows that this file is contained in an archive.  */
            newp->fd = -1;
            /* Store the ELF descriptor.  */
            newp->elf = arelf;
            /* Show that we are open for business.  */
            newp->status = in_archive;

            /* Now read the file and add all the symbols.  */
            res = file_process2 (newp);
            if (unlikely (res != 0))
            return res;

            any_used = true;
          }
      }

      if (++nround == 1)
      {
        /* This is an archive therefore it must have a number.  */
        assert (fileinfo->archive_seq != 0);
        ld_state.last_archive_used = fileinfo->archive_seq;
      }
    }
  while (any_used);

  return res;
}


static int
file_process2 (struct usedfiles *fileinfo)
{
  int res;

  if (likely (elf_kind (fileinfo->elf) == ELF_K_ELF))
    {
      /* The first time we get here we read the ELF header.  */
#if NATIVE_ELF != 0
      if (likely (fileinfo->ehdr == NULL))
#else
      if (likely (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_NONE))
#endif
      {
        XElf_Ehdr *ehdr;
#if NATIVE_ELF != 0
        ehdr = xelf_getehdr (fileinfo->elf, fileinfo->ehdr);
#else
        xelf_getehdr_copy (fileinfo->elf, ehdr, fileinfo->ehdr);
#endif
        if (ehdr == NULL)
          {
            fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"),
                   fileinfo->rfname, __FILE__, __LINE__);
            fileinfo->status = closed;
            return 1;
          }

        if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL
            && unlikely (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_DYN))
          /* XXX Add ebl* function to query types which are allowed
             to link in.  */
          {
            char buf[64];

            print_file_name (stderr, fileinfo, 1, 0);
            fprintf (stderr,
                   gettext ("file of type %s cannot be linked in\n"),
                   ebl_object_type_name (ld_state.ebl,
                                   FILEINFO_EHDR (fileinfo->ehdr).e_type,
                                   buf, sizeof (buf)));
            fileinfo->status = closed;
            return 1;
          }

        /* Make sure the file type matches the backend.  */
        if (FILEINFO_EHDR (fileinfo->ehdr).e_machine
            != ebl_get_elfmachine (ld_state.ebl))
          {
            fprintf (stderr, gettext ("\
%s: input file incompatible with ELF machine type %s\n"),
                   fileinfo->rfname,
                   ebl_backend_name (ld_state.ebl));
            fileinfo->status = closed;
            return 1;
          }

        /* Determine the section header string table section index.  */
        if (unlikely (elf_getshstrndx (fileinfo->elf, &fileinfo->shstrndx)
                  < 0))
          {
            fprintf (stderr, gettext ("\
%s: cannot get section header string table index: %s\n"),
                   fileinfo->rfname, elf_errmsg (-1));
            fileinfo->status = closed;
            return 1;
          }
      }

      /* Now handle the different types of files.  */
      if (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_REL)
      {
        /* Add all the symbol.  Relocatable files have symbol
           tables.  */
        res = add_relocatable_file (fileinfo, SHT_SYMTAB);
      }
      else
      {
        bool has_l_name = fileinfo->file_type == archive_file_type;

        assert (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN);

        /* If the file is a DT_NEEDED dependency then the type is
           already correctly specified.  */
        if (fileinfo->file_type != dso_needed_file_type)
          fileinfo->file_type = dso_file_type;

        /* We cannot use DSOs when generating relocatable objects.  */
        if (ld_state.file_type == relocatable_file_type)
          {
            error (0, 0, gettext ("\
cannot use DSO '%s' when generating relocatable object file"),
                 fileinfo->fname);
            return 1;
          }

        /* Add all the symbols.  For DSOs we are looking at the
           dynamic symbol table.  */
        res = add_relocatable_file (fileinfo, SHT_DYNSYM);

        /* We always have to have a dynamic section.  */
        assert (fileinfo->dynscn != NULL);

        /* We have to remember the dependencies for this object.  It
           is necessary to look them up.  */
        XElf_Shdr_vardef (dynshdr);
        xelf_getshdr (fileinfo->dynscn, dynshdr);

        Elf_Data *dyndata = elf_getdata (fileinfo->dynscn, NULL);
        /* XXX Should we flag the failure to get the dynamic section?  */
        if (dynshdr != NULL)
          {
            int cnt = dynshdr->sh_size / dynshdr->sh_entsize;
            XElf_Dyn_vardef (dyn);

            while (--cnt >= 0)
            {
              xelf_getdyn (dyndata, cnt, dyn);
              if (dyn != NULL)
                {
                  if(dyn->d_tag == DT_NEEDED)
                  {
                    struct usedfiles *newp;

                    newp = ld_new_inputfile (elf_strptr (fileinfo->elf,
                                                 dynshdr->sh_link,
                                                 dyn->d_un.d_val),
                                       dso_needed_file_type);

                    /* Enqueue the newly found dependencies.  */
                    // XXX Check that there not already a file with the
                    // same name.
                    CSNGL_LIST_ADD_REAR (ld_state.needed, newp);
                  }
                  else if (dyn->d_tag == DT_SONAME)
                  {
                    /* We use the DT_SONAME (this is what's there
                       for).  */
                    fileinfo->soname = elf_strptr (fileinfo->elf,
                                           dynshdr->sh_link,
                                           dyn->d_un.d_val);
                    has_l_name = false;
                  }
                }
            }
          }

        /* Construct the file name if the DSO has no SONAME and the
           file name comes from a -lXX parameter on the comment
           line.  */
        if (unlikely (has_l_name))
          {
            /* The FNAME is the parameter the user specified on the
             command line.  We prepend "lib" and append ".so".  */
            size_t len = strlen (fileinfo->fname) + 7;
            char *newp;

            newp = (char *) obstack_alloc (&ld_state.smem, len);
            strcpy (stpcpy (stpcpy (newp, "lib"), fileinfo->fname), ".so");

            fileinfo->soname = newp;
          }
      }
    }
  else if (likely (elf_kind (fileinfo->elf) == ELF_K_AR))
    {
      if (unlikely (ld_state.extract_rule == allextract))
      /* Which this option enabled we have to add all the object
         files in the archive.  */
      res = add_whole_archive (fileinfo);
      else if (ld_state.file_type == relocatable_file_type)
      {
        /* When generating a relocatable object we don't find files
           in archives.  */
        if (verbose)
          error (0, 0, gettext ("input file '%s' ignored"), fileinfo->fname);

        res = 0;
      }
      else
      /* Extract only the members from the archive which are
         currently referenced by unresolved symbols.  */
      res = extract_from_archive (fileinfo);
    }
  else
    /* This should never happen, we know about no other types.  */
    abort ();

  return res;
}


/* Process a given file.  The first parameter is a file descriptor for
   the file which can be -1 to indicate the file has not yet been
   found.  The second parameter describes the file to be opened, the
   last one is the state of the linker which among other information
   contain the paths we look at.  */
static int
ld_generic_file_process (int fd, struct usedfiles *fileinfo,
                   struct ld_state *statep, struct usedfiles **nextp)
{
  int res = 0;

  /* By default we go to the next file in the list.  */
  *nextp = fileinfo->next;

  /* Set the flag to signal we are looking for a group start.  */
  if (unlikely (fileinfo->group_start))
    {
      ld_state.group_start_requested = true;
      fileinfo->group_start = false;
    }

  /* If the file isn't open yet, open it now.  */
  if (likely (fileinfo->status == not_opened))
    {
      bool fd_passed = true;

      if (likely (fd == -1))
      {
        /* Find the file ourselves.  */
        int err = open_along_path (fileinfo);
        if (unlikely (err != 0))
          /* We allow libraries and DSOs to be named more than once.
             Don't report an error to the caller.  */
          return err == EAGAIN ? 0 : err;

        fd_passed = false;
      }
      else
      fileinfo->fd = fd;

      /* Remember where we got the descriptor from.  */
      fileinfo->fd_passed = fd_passed;

      /* We found the file.  Now test whether it is a file type we can
       handle.

       XXX Do we have to have the ability to start from a given
       position in the search path again to look for another file if
       the one found has not the right type?  */
      res = open_elf (fileinfo, elf_begin (fileinfo->fd,
                                 is_dso_p (fileinfo->fd)
                                 ? ELF_C_READ_MMAP
                                 : ELF_C_READ_MMAP_PRIVATE, NULL));
      if (unlikely (res != 0))
      return res;
    }

  /* Now that we have opened the file start processing it.  */
  if (likely (fileinfo->status != closed))
    res = file_process2 (fileinfo);

  /* Determine which file to look at next.  */
  if (unlikely (fileinfo->group_backref != NULL))
    {
      /* We only go back if an archive other than the one we would go
       back to has been used in the last round.  */
      if (ld_state.last_archive_used > fileinfo->group_backref->archive_seq)
      {
        *nextp = fileinfo->group_backref;
        ld_state.last_archive_used = 0;
      }
      else
      {
        /* If we come here this means that the archives we read so
           far are not needed anymore.  We can free some of the data
           now.  */
        struct usedfiles *runp = ld_state.archives;

        do
          {
            /* We don't need the ELF descriptor anymore.  Unless there
             are no files from the archive used this will not free
             the whole file but only some data structures.  */
            elf_end (runp->elf);
            runp->elf = NULL;

            runp = runp->next;
          }
        while (runp != fileinfo->next);
      }
    }
  else if (unlikely (fileinfo->group_end))
    {
      /* This is the end of a group.  We possibly of to go back.
       Determine which file we would go back to and see whether it
       makes sense.  If there has not been an archive we don't have
       to do anything.  */
      if (!ld_state.group_start_requested)
      {
        if (ld_state.group_start_archive != ld_state.tailarchives)
          /* The loop would include more than one archive, add the
             pointer.  */
          {
            *nextp = ld_state.tailarchives->group_backref =
            ld_state.group_start_archive;
            ld_state.last_archive_used = 0;
          }
        else
          /* We might still have to go back to the beginning of the
             group if since the last archive other files have been
             added.  But we go back exactly once.  */
          if (ld_state.tailarchives != fileinfo)
            {
            *nextp = ld_state.group_start_archive;
            ld_state.last_archive_used = 0;
            }
      }

      /* Clear the flags.  */
      ld_state.group_start_requested = false;
      fileinfo->group_end = false;
    }

  return res;
}


/* Library names passed to the linker as -lXX represent files named
   libXX.YY.  The YY part can have different forms, depending on the
   platform.  The generic set is .so and .a (in this order).  */
static const char **
ld_generic_lib_extensions (struct ld_state *statep __attribute__ ((__unused__)))
{
  static const char *exts[] =
    {
      ".so", ".a", NULL
    };

  return exts;
}


/* Flag unresolved symbols.  */
static int
ld_generic_flag_unresolved (struct ld_state *statep)
{
  int retval = 0;

  if (ld_state.nunresolved_nonweak > 0)
    {
      /* Go through the list and determine the unresolved symbols.  */
      struct symbol *first;
      struct symbol *s;

      s = first = ld_state.unresolved->next;
      do
      {
        if (! s->defined && ! s->weak)
          {
            /* Two special symbol we recognize: the symbol for the
             GOT and the dynamic section.  */
            if (strcmp (s->name, "_GLOBAL_OFFSET_TABLE_") == 0
              || strcmp (s->name, "_DYNAMIC") == 0)
            {
              /* We will have to fill in more information later.  */
              ld_state.need_got = true;

              /* Remember that we found it.  */
              if (s->name[1] == 'G')
                ld_state.got_symbol = s;
              else
                ld_state.dyn_symbol = s;
            }
            else if (ld_state.file_type != dso_file_type || !ld_state.nodefs)
            {
              /* XXX The error message should get better.  It should use
                 the debugging information if present to tell where in the
                 sources the undefined reference is.  */
              error (0, 0, gettext ("undefined symbol `%s' in %s"),
                   s->name, s->file->fname);

              retval = 1;
            }
          }

        /* We cannot decide here what to do with undefined
           references which will come from DSO since we do not know
           what kind of symbol we expect.  Only when looking at the
           relocations we can see whether we need a PLT entry or
           only a GOT entry.  */

        s = s->next;
      }
      while (s != first);
    }

  return retval;
}


/* Close the given file.  */
static int
ld_generic_file_close (struct usedfiles *fileinfo, struct ld_state *statep)
{
  /* Close the ELF descriptor.  */
  elf_end (fileinfo->elf);

  /* If we have opened the file descriptor close it.  But we might
     have done this already in which case FD is -1.  */
  if (!fileinfo->fd_passed && fileinfo->fd != -1)
    close (fileinfo->fd);

  /* We allocated the resolved file name.  */
  if (fileinfo->fname != fileinfo->rfname)
    free ((char *) fileinfo->rfname);

  return 0;
}


static void
new_generated_scn (enum scn_kind kind, const char *name, int type, int flags,
               int entsize, int align)
{
  struct scnhead *newp;

  newp = (struct scnhead *) obstack_calloc (&ld_state.smem,
                                  sizeof (struct scnhead));
  newp->kind = kind;
  newp->name = name;
  newp->nameent = ebl_strtabadd (ld_state.shstrtab, name, 0);
  newp->type = type;
  newp->flags = flags;
  newp->entsize = entsize;
  newp->align = align;
  newp->grp_signature = NULL;
  newp->used = true;

  /* All is well.  Create now the data for the section and insert it
     into the section table.  */
  ld_section_tab_insert (&ld_state.section_tab, elf_hash (name), newp);
}


/* Create the sections which are generated by the linker and are not
   present in the input file.  */
static void
ld_generic_generate_sections (struct ld_state *statep)
{
  /* The relocation section type.  */
  int rel_type = REL_TYPE (&ld_state) == DT_REL ? SHT_REL : SHT_RELA;

  /* When building dynamically linked object we have to include a
     section containing a string describing the interpreter.  This
     should be at the very beginning of the file together with the
     other information the ELF loader (kernel or wherever) has to look
     at.  We put it as the first section in the file.

     We also have to create the dynamic segment which is a special
     section the dynamic linker locates through an entry in the
     program header.  */
  if (dynamically_linked_p ())
    {
      /* Use any versioning (defined or required)?  */
      bool use_versioning = false;
      /* Use version requirements?  */
      bool need_version = false;

      /* First the .interp section.  */
      if (ld_state.interp != NULL || ld_state.file_type != dso_file_type)
      new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC,
                     0, 1);

      /* Now the .dynamic section.  */
      new_generated_scn (scn_dot_dynamic, ".dynamic", SHT_DYNAMIC,
                   DYNAMIC_SECTION_FLAGS (&ld_state),
                   xelf_fsize (ld_state.outelf, ELF_T_DYN, 1),
                   xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));

      /* We will need in any case the dynamic symbol table (even in
       the unlikely case that no symbol is exported or referenced
       from a DSO).  */
      ld_state.need_dynsym = true;
      new_generated_scn (scn_dot_dynsym, ".dynsym", SHT_DYNSYM, SHF_ALLOC,
                   xelf_fsize (ld_state.outelf, ELF_T_SYM, 1),
                   xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));
      /* It comes with a string table.  */
      new_generated_scn (scn_dot_dynstr, ".dynstr", SHT_STRTAB, SHF_ALLOC,
                   0, 1);
      /* And a hashing table.  */
      // XXX For Linux/Alpha we need other sizes unless they change...
      new_generated_scn (scn_dot_hash, ".hash", SHT_HASH, SHF_ALLOC,
                   sizeof (Elf32_Word), sizeof (Elf32_Word));

      /* Create the section associated with the PLT if necessary.  */
      if (ld_state.nplt > 0)
      {
        /* Create the .plt section.  */
        /* XXX We might need a function which returns the section flags.  */
        new_generated_scn (scn_dot_plt, ".plt", SHT_PROGBITS,
                       SHF_ALLOC | SHF_EXECINSTR,
                       /* XXX Is the size correct?  */
                       xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1),
                       xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));

        /* Create the relocation section for the .plt.  This is always
           separate even if the other relocation sections are combined.  */
        new_generated_scn (scn_dot_pltrel, ".rel.plt", rel_type, SHF_ALLOC,
                       rel_type == SHT_REL
                       ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1)
                       : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1),
                       xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));

        /* This means we will also need the .got section.  */
        ld_state.need_got = true;

        /* Mark all used DSOs as used.  Determine whether any referenced
           object uses symbol versioning.  */
        if (ld_state.from_dso != NULL)
          {
            struct symbol *srunp = ld_state.from_dso;

            do
            {
              srunp->file->used = true;

              if (srunp->file->verdefdata != NULL)
                {
                  XElf_Versym versym;

                  /* The input DSO uses versioning.  */
                  use_versioning = true;
                  /* We reference versions.  */
                  need_version = true;

                  if (xelf_getversym_copy (srunp->file->versymdata,
                                     srunp->symidx, versym) == NULL)
                  assert (! "xelf_getversym failed");

                  /* We cannot link explicitly with an older
                   version of a symbol.  */
                  assert ((versym & 0x8000) == 0);
                  /* We cannot reference local (index 0) or plain
                   global (index 1) versions.  */
                  assert (versym > 1);

                  /* Check whether we have already seen the
                   version and if not add it to the referenced
                   versions in the output file.  */
                  if (! srunp->file->verdefused[versym])
                  {
                    srunp->file->verdefused[versym] = 1;

                    if (++srunp->file->nverdefused == 1)
                      /* Count the file if it is using versioning.  */
                      ++ld_state.nverdeffile;
                    ++ld_state.nverdefused;
                  }
                }
            }
            while ((srunp = srunp->next) != ld_state.from_dso);
          }

        /* Create the sections used to record version dependencies.  */
        if (need_version)
          new_generated_scn (scn_dot_version_r, ".gnu.version_r",
                         SHT_GNU_verneed, SHF_ALLOC, 0,
                         xelf_fsize (ld_state.outelf, ELF_T_WORD, 1));
      }

      /* Now count the used DSOs since this is what the user
       wants.  */
      int ndt_needed = 0;
      if (ld_state.ndsofiles > 0)
      {
        struct usedfiles *frunp = ld_state.dsofiles;

        do
          if (! frunp->as_needed || frunp->used)
            {
            ++ndt_needed;
            if (frunp->lazyload)
              /* We have to create another dynamic section
                 entry for the DT_POSFLAG_1 entry.

                 XXX Once more functionality than the lazyloading
                 flag are suppported the test must be
                 extended.  */
              ++ndt_needed;
            }
        while ((frunp = frunp->next) != ld_state.dsofiles);
      }

      if (use_versioning)
      new_generated_scn (scn_dot_version, ".gnu.version", SHT_GNU_versym,
                     SHF_ALLOC,
                     xelf_fsize (ld_state.outelf, ELF_T_HALF, 1),
                     xelf_fsize (ld_state.outelf, ELF_T_HALF, 1));

      /* We need some entries all the time.  */
      ld_state.ndynamic = (7 + (ld_state.runpath != NULL
                        || ld_state.rpath != NULL)
                     + ndt_needed
                     + (ld_state.init_symbol != NULL ? 1 : 0)
                     + (ld_state.fini_symbol != NULL ? 1 : 0)
                     + (use_versioning ? 1 : 0)
                     + (need_version ? 2 : 0)
                     + (ld_state.nplt > 0 ? 4 : 0)
                     + (ld_state.relsize_total > 0 ? 3 : 0));
    }

  /* When creating a relocatable file or when we are not stripping the
     output file we create a symbol table.  */
  ld_state.need_symtab = (ld_state.file_type == relocatable_file_type
                    || ld_state.strip == strip_none);

  /* Add the .got section if needed.  */
  if (ld_state.need_got)
    /* XXX We might need a function which returns the section flags.  */
    new_generated_scn (scn_dot_got, ".got", SHT_PROGBITS,
                   SHF_ALLOC | SHF_WRITE,
                   xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1),
                   xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));

  /* Add the .rel.dyn section.  */
  if (ld_state.relsize_total > 0)
    new_generated_scn (scn_dot_dynrel, ".rel.dyn", rel_type, SHF_ALLOC,
                   rel_type == SHT_REL
                   ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1)
                   : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1),
                   xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));
}


/* Callback function registered with on_exit to make sure the temporary
   files gets removed if something goes wrong.  */
static void
remove_tempfile (int status, void *arg)
{
  if (status != 0 && ld_state.tempfname != NULL)
    unlink (ld_state.tempfname);
}


/* Create the output file.  The file name is given or "a.out".  We
   create as much of the ELF structure as possible.  */
static int
ld_generic_open_outfile (struct ld_state *statep, int machine, int klass,
                   int data)
{
  /* We do not create the new file right away with the final name.
     This would destroy an existing file with this name before a
     replacement is finalized.  We create instead a temporary file in
     the same directory.  */
  if (ld_state.outfname == NULL)
    ld_state.outfname = "a.out";

  size_t outfname_len = strlen (ld_state.outfname);
  char *tempfname = (char *) obstack_alloc (&ld_state.smem,
                                  outfname_len + sizeof (".XXXXXX"));
  ld_state.tempfname = tempfname;

  int fd;
  int try = 0;
  while (1)
    {
      strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXXXX");

      /* The use of mktemp() here is fine.  We do not want to use
       mkstemp() since then the umask isn't used.  And the output
       file will have these permissions anyhow.  Any intruder could
       change the file later if it would be possible now.  */
      if (mktemp (tempfname) != NULL
        && (fd = open (tempfname, O_RDWR | O_EXCL | O_CREAT | O_NOFOLLOW,
                   ld_state.file_type == relocatable_file_type
                   ? DEFFILEMODE : ACCESSPERMS)) != -1)
      break;

      /* Failed this round.  We keep trying a number of times.  */
      if (++try >= 10)
      error (EXIT_FAILURE, errno, gettext ("cannot create output file"));
    }
  ld_state.outfd = fd;

  /* Make sure we remove the temporary file in case something goes
     wrong.  */
  on_exit (remove_tempfile, NULL);

  /* Create the ELF file data for the output file.  */
  Elf *elf = ld_state.outelf = elf_begin (fd,
                                conserve_memory
                                ? ELF_C_WRITE : ELF_C_WRITE_MMAP,
                                NULL);
  if (elf == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot create ELF descriptor for output file: %s"),
         elf_errmsg (-1));

  /* Create the basic data structures.  */
  if (! xelf_newehdr (elf, klass))
    /* Couldn't create the ELF header.  Very bad.  */
    error (EXIT_FAILURE, 0,
         gettext ("could not create ELF header for output file: %s"),
         elf_errmsg (-1));

  /* And get the current header so that we can modify it.  */
  XElf_Ehdr_vardef (ehdr);
  xelf_getehdr (elf, ehdr);
  assert (ehdr != NULL);

  /* Set the machine type.  */
  ehdr->e_machine = machine;

  /* Modify it according to the info we have here and now.  */
  if (ld_state.file_type == executable_file_type)
    ehdr->e_type = ET_EXEC;
  else if (ld_state.file_type == dso_file_type)
    ehdr->e_type = ET_DYN;
  else
    {
      assert (ld_state.file_type == relocatable_file_type);
      ehdr->e_type = ET_REL;
    }

  /* Set the ELF version.  */
  ehdr->e_version = EV_CURRENT;

  /* Set the endianness.  */
  ehdr->e_ident[EI_DATA] = data;

  /* Write the ELF header information back.  */
  (void) xelf_update_ehdr (elf, ehdr);

  return 0;
}


/* We compute the offsets of the various copied objects and the total
   size of the memory needed.  */
// XXX The method used here is simple: go from front to back and pack
// the objects in this order.  A more space efficient way would
// actually trying to pack the objects as dense as possible.  But this
// is more expensive.
static void
compute_copy_reloc_offset (XElf_Shdr *shdr)
{
  struct symbol *runp = ld_state.from_dso;
  assert (runp != NULL);

  XElf_Off maxalign = 1;
  XElf_Off offset = 0;

  do
    if (runp->need_copy)
      {
      /* Determine alignment for the symbol.  */
      // XXX The question is how?  The symbol record itself does not
      // have the information.  So we have to be conservative and
      // assume the alignment of the section the symbol is in.

      // XXX We can be more precise.  Use the offset from the beginning
      // of the section and determine the largest power of two with
      // module zero.
      XElf_Off symalign = MAX (SCNINFO_SHDR (runp->file->scninfo[runp->scndx].shdr).sh_addralign, 1);
      /* Keep track of the maximum alignment requirement.  */
      maxalign = MAX (maxalign, symalign);

      /* Align current position.  */
      offset = (offset + symalign - 1) & ~(symalign - 1);

      runp->merge.value = offset;

      offset += runp->size;
      }
  while ((runp = runp->next) != ld_state.from_dso);

  shdr->sh_type = SHT_NOBITS;
  shdr->sh_size = offset;
  shdr->sh_addralign = maxalign;
}


static void
compute_common_symbol_offset (XElf_Shdr *shdr)
{
  struct symbol *runp = ld_state.common_syms;
  assert (runp != NULL);

  XElf_Off maxalign = 1;
  XElf_Off offset = 0;

  do
    {
      /* Determine alignment for the symbol.  */
      XElf_Off symalign = runp->merge.value;

      /* Keep track of the maximum alignment requirement.  */
      maxalign = MAX (maxalign, symalign);

      /* Align current position.  */
      offset = (offset + symalign - 1) & ~(symalign - 1);

      runp->merge.value = offset;

      offset += runp->size;
    }
  while ((runp = runp->next) != ld_state.common_syms);

  shdr->sh_type = SHT_NOBITS;
  shdr->sh_size = offset;
  shdr->sh_addralign = maxalign;
}


static void
sort_sections_generic (void)
{
  /* XXX TBI */
  abort ();
}


static int
match_section (const char *osectname, struct filemask_section_name *sectmask,
             struct scnhead **scnhead, bool new_section, size_t segment_nr)
{
  struct scninfo *prevp;
  struct scninfo *runp;
  struct scninfo *notused;

  if (fnmatch (sectmask->section_name->name, (*scnhead)->name, 0) != 0)
    /* The section name does not match.  */
    return new_section;

  /* If this is a section generated by the linker it doesn't contain
     the regular information (i.e., input section data etc) and must
     be handle special.  */
  if ((*scnhead)->kind != scn_normal)
    {
      (*scnhead)->name = osectname;
      (*scnhead)->segment_nr = segment_nr;

      /* We have to count note section since they get their own
       program header entry.  */
      if ((*scnhead)->type == SHT_NOTE)
      ++ld_state.nnotesections;

      ld_state.allsections[ld_state.nallsections++] = (*scnhead);
      return true;
    }

  /* Now we have to match the file names of the input files.  Some of
     the sections here might not match.    */
  runp = (*scnhead)->last->next;
  prevp = (*scnhead)->last;
  notused = NULL;

  do
    {
      /* Base of the file name the section comes from.  */
      const char *brfname = basename (runp->fileinfo->rfname);

      /* If the section isn't used, the name doesn't match the positive
       inclusion list, or the name does match the negative inclusion
       list, ignore the section.  */
      if (!runp->used
        || (sectmask->filemask != NULL
            && fnmatch (sectmask->filemask, brfname, 0) != 0)
        || (sectmask->excludemask != NULL
            && fnmatch (sectmask->excludemask, brfname, 0) == 0))
      {
        /* This file does not match the file name masks.  */
        if (notused == NULL)
          notused = runp;

        prevp = runp;
        runp = runp->next;
        if (runp == notused)
          runp = NULL;
      }
      /* The section fulfills all requirements, add it to the output
       file with the correct section name etc.  */
      else
      {
        struct scninfo *found = runp;

        /* Remove this input section data buffer from the list.  */
        if (prevp != runp)
          runp = prevp->next = runp->next;
        else
          {
            free (*scnhead);
            *scnhead = NULL;
            runp = NULL;
          }

        /* Create a new section for the output file if the 'new_section'
           flag says so.  Otherwise append the buffer to the last
           section which we created in one of the last calls.  */
        if (new_section)
          {
            struct scnhead *newp;

            newp = (struct scnhead *) obstack_calloc (&ld_state.smem,
                                          sizeof (*newp));
            newp->kind = scn_normal;
            newp->name = osectname;
            newp->type = SCNINFO_SHDR (found->shdr).sh_type;
            /* Executable or DSO do not have section groups.  Drop that
             information.  */
            newp->flags = SCNINFO_SHDR (found->shdr).sh_flags & ~SHF_GROUP;
            newp->segment_nr = segment_nr;
            newp->last = found->next = found;
            newp->used = true;
            newp->relsize = found->relsize;
            newp->entsize = SCNINFO_SHDR (found->shdr).sh_entsize;

            /* We have to count note section since they get their own
             program header entry.  */
            if (newp->type == SHT_NOTE)
            ++ld_state.nnotesections;

            ld_state.allsections[ld_state.nallsections++] = newp;
            new_section = false;
          }
        else
          {
            struct scnhead *queued;

            queued = ld_state.allsections[ld_state.nallsections - 1];

            found->next = queued->last->next;
            queued->last = queued->last->next = found;

            /* If the linker script forces us to add incompatible
             sections together do so.  But reflect this in the
             type and flags of the resulting file.  */
            if (queued->type != SCNINFO_SHDR (found->shdr).sh_type)
            /* XXX Any better choice?  */
            queued->type = SHT_PROGBITS;
            if (queued->flags != SCNINFO_SHDR (found->shdr).sh_flags)
            /* Executable or DSO do not have section groups.  Drop that
               information.  */
            queued->flags = ebl_sh_flags_combine (ld_state.ebl,
                                          queued->flags,
                                          SCNINFO_SHDR (found->shdr).sh_flags
                                          & ~SHF_GROUP);

            /* Accumulate the relocation section size.  */
            queued->relsize += found->relsize;
          }
      }
    }
  while (runp != NULL);

  return new_section;
}


static void
sort_sections_lscript (void)
{
  struct scnhead *temp[ld_state.nallsections];

  /* Make a copy of the section head pointer array.  */
  memcpy (temp, ld_state.allsections,
        ld_state.nallsections * sizeof (temp[0]));
  size_t nallsections = ld_state.nallsections;

  /* Convert the output segment list in a single-linked list.  */
  struct output_segment *segment = ld_state.output_segments->next;
  ld_state.output_segments->next = NULL;
  ld_state.output_segments = segment;

  /* Put the sections in the correct order in the array in the state
     structure.  This might involve merging of sections and also
     renaming the containing section in the output file.  */
  ld_state.nallsections = 0;
  size_t segment_nr;
  size_t last_writable = ~0ul;
  for (segment_nr = 0; segment != NULL; segment = segment->next, ++segment_nr)
    {
      struct output_rule *orule;

      for (orule = segment->output_rules; orule != NULL; orule = orule->next)
      if (orule->tag == output_section)
        {
          struct input_rule *irule;
          bool new_section = true;

          for (irule = orule->val.section.input; irule != NULL;
             irule = irule->next)
            if (irule->tag == input_section)
            {
              size_t cnt;

              for (cnt = 0; cnt < nallsections; ++cnt)
                if (temp[cnt] != NULL)
                  new_section =
                  match_section (orule->val.section.name,
                               irule->val.section, &temp[cnt],
                               new_section, segment_nr);
            }
        }

      if ((segment->mode & PF_W) != 0)
      last_writable = ld_state.nallsections - 1;
    }

  /* In case we have to create copy relocations or we have common
     symbols, find the last writable segment and add one more data
     block.  It will be a NOBITS block and take up no disk space.
     This is why it is important to get the last block.  */
  if (ld_state.ncopy > 0 || ld_state.common_syms !=  NULL)
    {
      if (last_writable == ~0ul)
      error (EXIT_FAILURE, 0, "no writable segment");

      if (ld_state.allsections[last_writable]->type != SHT_NOBITS)
      {
        /* Make room in the ALLSECTIONS array for a new section.
           There is guaranteed room in the array.  We add the new
           entry after the last writable section.  */
        ++last_writable;
        memmove (&ld_state.allsections[last_writable + 1],
               &ld_state.allsections[last_writable],
               (ld_state.nallsections - last_writable)
               * sizeof (ld_state.allsections[0]));

        ld_state.allsections[last_writable] = (struct scnhead *)
          obstack_calloc (&ld_state.smem, sizeof (struct scnhead));

        /* Name for the new section.  */
        ld_state.allsections[last_writable]->name = ".bss";
        /* Type: NOBITS.  */
        ld_state.allsections[last_writable]->type = SHT_NOBITS;
        /* Same segment as the last writable section.  */
        ld_state.allsections[last_writable]->segment_nr
          = ld_state.allsections[last_writable - 1]->segment_nr;
      }
    }

  /* Create common symbol data block.  */
  if (ld_state.ncopy > 0)
    {
#if NATIVE_ELF
      struct scninfo *si = (struct scninfo *)
      obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr));
      si->shdr = (XElf_Shdr *) (si + 1);
#else
      struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem,
                                                sizeof (*si));
#endif

      /* Get the information regarding the symbols with copy relocations.  */
      compute_copy_reloc_offset (&SCNINFO_SHDR (si->shdr));

      /* This section is needed.  */
      si->used = true;
      /* Remember for later the section data structure.  */
      ld_state.copy_section = si;

      if (likely (ld_state.allsections[last_writable]->last != NULL))
      {
        si->next = ld_state.allsections[last_writable]->last->next;
        ld_state.allsections[last_writable]->last->next = si;
        ld_state.allsections[last_writable]->last = si;
      }
      else
      ld_state.allsections[last_writable]->last = si->next = si;
    }

  /* Create common symbol data block.  */
  if (ld_state.common_syms != NULL)
    {
#if NATIVE_ELF
      struct scninfo *si = (struct scninfo *)
      obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr));
      si->shdr = (XElf_Shdr *) (si + 1);
#else
      struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem,
                                                sizeof (*si));
#endif

      /* Get the information regarding the symbols with copy relocations.  */
      compute_common_symbol_offset (&SCNINFO_SHDR (si->shdr));

      /* This section is needed.  */
      si->used = true;
      /* Remember for later the section data structure.  */
      ld_state.common_section = si;

      if (likely (ld_state.allsections[last_writable]->last != NULL))
      {
        si->next = ld_state.allsections[last_writable]->last->next;
        ld_state.allsections[last_writable]->last->next = si;
        ld_state.allsections[last_writable]->last = si;
      }
      else
      ld_state.allsections[last_writable]->last = si->next = si;
    }
}


/* Create the output sections now.  This requires knowledge about all
   the sections we will need.  It may be necessary to sort sections in
   the order they are supposed to appear in the executable.  The
   sorting use many different kinds of information to optimize the
   resulting binary.  Important is to respect segment boundaries and
   the needed alignment.  The mode of the segments will be determined
   afterwards automatically by the output routines.

   The generic sorting routines work in one of two possible ways:

   - if a linker script specifies the sections to be used in the
     output and assigns them to a segment this information is used;

   - otherwise the linker will order the sections based on permissions
     and some special knowledge about section names.*/
static void
ld_generic_create_sections (struct ld_state *statep)
{
  struct scngroup *groups;
  size_t cnt;

  /* For relocatable object we don't have to bother sorting the
     sections and we do want to preserve the relocation sections as
     they appear in the input files.  */
  if (ld_state.file_type != relocatable_file_type)
    {
      /* Collect all the relocation sections.  They are handled
       separately.  */
      struct scninfo *list = NULL;
      for (cnt = 0; cnt < ld_state.nallsections; ++cnt)
      if ((ld_state.allsections[cnt]->type == SHT_REL
           || ld_state.allsections[cnt]->type == SHT_RELA)
          /* The generated relocation sections are not of any
             interest here.  */
          && ld_state.allsections[cnt]->last != NULL)
        {
          if (list == NULL)
            list = ld_state.allsections[cnt]->last;
          else
            {
            /* Merge the sections list.  */
            struct scninfo *first = list->next;
            list->next = ld_state.allsections[cnt]->last->next;
            ld_state.allsections[cnt]->last->next = first;
            list = ld_state.allsections[cnt]->last;
            }

          /* Remove the entry from the section list.  */
          ld_state.allsections[cnt] = NULL;
        }
      ld_state.rellist = list;

      if (ld_state.output_segments == NULL)
      /* Sort using builtin rules.  */
      sort_sections_generic ();
      else
      sort_sections_lscript ();
    }

  /* Now iterate over the input sections and create the sections in the
     order they are required in the output file.  */
  for (cnt = 0; cnt < ld_state.nallsections; ++cnt)
    {
      struct scnhead *head = ld_state.allsections[cnt];
      Elf_Scn *scn;
      XElf_Shdr_vardef (shdr);

      /* Don't handle unused sections.  */
      if (!head->used)
      continue;

      /* We first have to create the section group if necessary.
       Section group sections must come (in section index order)
       before any of the section contained.  This all is necessary
       only for relocatable object as other object types are not
       allowed to contain section groups.  */
      if (ld_state.file_type == relocatable_file_type
        && unlikely (head->flags & SHF_GROUP))
      {
        /* There is at least one section which is contained in a
           section group in the input file.  This means we must
           create a section group here as well.  The only problem is
           that not all input files have to have to same kind of
           partitioning of the sections.  I.e., sections A and B in
           one input file and sections B and C in another input file
           can be in one group.  That will result in a group
           containing the sections A, B, and C in the output
           file.  */
        struct scninfo *runp;
        Elf32_Word here_groupidx = 0;
        struct scngroup *here_group;
        struct member *newp;

        /* First check whether any section is already in a group.
           In this case we have to add this output section, too.  */
        runp = head->last;
        do
          {
            assert (runp->grpid != 0);

            here_groupidx = runp->fileinfo->scninfo[runp->grpid].outscnndx;
            if (here_groupidx != 0)
            break;
          }
        while ((runp = runp->next) != head->last);

        if (here_groupidx == 0)
          {
            /* We need a new section group section.  */
            scn = elf_newscn (ld_state.outelf);
            xelf_getshdr (scn, shdr);
            if (shdr == NULL)
            error (EXIT_FAILURE, 0,
                   gettext ("cannot create section for output file: %s"),
                   elf_errmsg (-1));

            here_group = (struct scngroup *) xmalloc (sizeof (*here_group));
            here_group->outscnidx = here_groupidx = elf_ndxscn (scn);
            here_group->nscns = 0;
            here_group->member = NULL;
            here_group->next = ld_state.groups;
            /* Pick a name for the section.  To keep it meaningful
             we use a name used in the input files.  If the
             section group in the output file should contain
             section which were in section groups of different
             names in the input files this is the users
             problem.  */
            here_group->nameent
            = ebl_strtabadd (ld_state.shstrtab,
                         elf_strptr (runp->fileinfo->elf,
                                   runp->fileinfo->shstrndx,
                                   SCNINFO_SHDR (runp->shdr).sh_name),
                         0);
            /* Signature symbol.  */
            here_group->symbol
            = runp->fileinfo->scninfo[runp->grpid].symbols;

            ld_state.groups = here_group;
          }
        else
          {
            /* Search for the group with this index.  */
            here_group = ld_state.groups;
            while (here_group->outscnidx != here_groupidx)
            here_group = here_group->next;
          }

        /* Add the new output section.  */
        newp = (struct member *) alloca (sizeof (*newp));
        newp->scn = head;
#ifndef NDT_NEEDED
        newp->next = NULL;
#endif
        CSNGL_LIST_ADD_REAR (here_group->member, newp);
        ++here_group->nscns;

        /* Store the section group index in all input files.  */
        runp = head->last;
        do
          {
            assert (runp->grpid != 0);

            if (runp->fileinfo->scninfo[runp->grpid].outscnndx == 0)
            runp->fileinfo->scninfo[runp->grpid].outscnndx = here_groupidx;
            else
            assert (runp->fileinfo->scninfo[runp->grpid].outscnndx
                  == here_groupidx);
          }
        while ((runp = runp->next) != head->last);
      }

      /* We'll use this section so get it's name in the section header
       string table.  */
      if (head->kind == scn_normal)
      head->nameent = ebl_strtabadd (ld_state.shstrtab, head->name, 0);

      /* Create a new section in the output file and add all data
       from all the sections we read.  */
      scn = elf_newscn (ld_state.outelf);
      head->scnidx = elf_ndxscn (scn);
      xelf_getshdr (scn, shdr);
      if (shdr == NULL)
      error (EXIT_FAILURE, 0,
             gettext ("cannot create section for output file: %s"),
             elf_errmsg (-1));

      assert (head->type != SHT_NULL);
      assert (head->type != SHT_SYMTAB);
      assert (head->type != SHT_DYNSYM || head->kind != scn_normal);
      assert (head->type != SHT_STRTAB || head->kind != scn_normal);
      assert (head->type != SHT_GROUP);
      shdr->sh_type = head->type;
      shdr->sh_flags = head->flags;
      shdr->sh_addralign = head->align;
      shdr->sh_entsize = head->entsize;
      assert (shdr->sh_entsize != 0 || (shdr->sh_flags & SHF_MERGE) == 0);
      (void) xelf_update_shdr (scn, shdr);

      /* We have to know the section index of the dynamic symbol table
       right away.  */
      if (head->kind == scn_dot_dynsym)
      ld_state.dynsymscnidx = elf_ndxscn (scn);
    }

  /* Actually create the section group sections.  */
  groups = ld_state.groups;
  while (groups != NULL)
    {
      Elf_Scn *scn;
      Elf_Data *data;
      Elf32_Word *grpdata;
      struct member *runp;

      scn = elf_getscn (ld_state.outelf, groups->outscnidx);
      assert (scn != NULL);

      data = elf_newdata (scn);
      if (data == NULL)
      error (EXIT_FAILURE, 0,
             gettext ("cannot create section for output file: %s"),
             elf_errmsg (-1));

      data->d_size = (groups->nscns + 1) * sizeof (Elf32_Word);
      data->d_buf = grpdata = (Elf32_Word *) xmalloc (data->d_size);
      data->d_type = ELF_T_WORD;
      data->d_version = EV_CURRENT;
      data->d_off = 0;
      /* XXX What better to use?  */
      data->d_align = sizeof (Elf32_Word);

      /* The first word in the section is the flag word.  */
      /* XXX Set COMDATA flag is necessary.  */
      grpdata[0] = 0;

      runp = groups->member->next;
      cnt = 1;
      do
      /* Fill in the index of the section.  */
      grpdata[cnt++] = runp->scn->scnidx;
      while ((runp = runp->next) != groups->member->next);

      groups = groups->next;
    }
}


static bool
reduce_symbol_p (XElf_Sym *sym, struct Ebl_Strent *strent)
{
  const char *str;
  const char *version;
  struct id_list search;
  struct id_list *verp;
  bool result = ld_state.default_bind_local;

  if (XELF_ST_BIND (sym->st_info) == STB_LOCAL || sym->st_shndx == SHN_UNDEF)
    /* We don't have to do anything to local symbols here.  */
    /* XXX Any section value in [SHN_LORESERVER,SHN_XINDEX) need
       special treatment?  */
    return false;

  /* XXX Handle other symbol bindings.  */
  assert (XELF_ST_BIND (sym->st_info) == STB_GLOBAL
        || XELF_ST_BIND (sym->st_info) == STB_WEAK);

  str = ebl_string (strent);
  version = strchr (str, VER_CHR);
  if (version != NULL)
    {
      search.id = strndupa (str, version - str);
      if (*++version == VER_CHR)
      /* Skip the second '@' signaling a default definition.  */
      ++version;
    }
  else
    {
      search.id = str;
      version = "";
    }

  verp = ld_version_str_tab_find (&ld_state.version_str_tab,
                          elf_hash (search.id), &search);
  while (verp != NULL)
    {
      /* We have this symbol in the version hash table.  Now match the
       version name.  */
      if (strcmp (verp->u.s.versionname, version) == 0)
      /* Match!  */
      return verp->u.s.local;

      verp = verp->next;
    }

  /* XXX Add test for wildcard version symbols.  */

  return result;
}


static XElf_Addr
eval_expression (struct expression *expr, XElf_Addr addr)
{
  XElf_Addr val = ~((XElf_Addr) 0);

  switch (expr->tag)
    {
    case exp_num:
      val = expr->val.num;
      break;

    case exp_sizeof_headers:
      {
      /* The 'elf_update' call determine the offset of the first
         section.  The the size of the header.  */
      XElf_Shdr_vardef (shdr);

      xelf_getshdr (elf_getscn (ld_state.outelf, 1), shdr);
      assert (shdr != NULL);

      val = shdr->sh_offset;
      }
      break;

    case exp_pagesize:
      val = ld_state.pagesize;
      break;

    case exp_id:
      /* We are here computing only address expressions.  It seems not
       to be necessary to handle any variable but ".".  Let's avoid
       the complication.  If it turns up to be needed we can add
       it.  */
      if (strcmp (expr->val.str, ".") != 0)
      error (EXIT_FAILURE, 0, gettext ("\
address computation expression contains variable '%s'"),
             expr->val.str);

      val = addr;
      break;

    case exp_mult:
      val = (eval_expression (expr->val.binary.left, addr)
           * eval_expression (expr->val.binary.right, addr));
      break;

    case exp_div:
      val = (eval_expression (expr->val.binary.left, addr)
           / eval_expression (expr->val.binary.right, addr));
      break;

    case exp_mod:
      val = (eval_expression (expr->val.binary.left, addr)
           % eval_expression (expr->val.binary.right, addr));
      break;

    case exp_plus:
      val = (eval_expression (expr->val.binary.left, addr)
           + eval_expression (expr->val.binary.right, addr));
      break;

    case exp_minus:
      val = (eval_expression (expr->val.binary.left, addr)
           - eval_expression (expr->val.binary.right, addr));
      break;

    case exp_and:
      val = (eval_expression (expr->val.binary.left, addr)
           & eval_expression (expr->val.binary.right, addr));
      break;

    case exp_or:
      val = (eval_expression (expr->val.binary.left, addr)
           | eval_expression (expr->val.binary.right, addr));
      break;

    case exp_align:
      val = eval_expression (expr->val.child, addr);
      if ((val & (val - 1)) != 0)
      error (EXIT_FAILURE, 0, gettext ("argument '%" PRIuMAX "' of ALIGN in address computation expression is no power of two"),
             (uintmax_t) val);
      val = (addr + val - 1) & ~(val - 1);
      break;
    }

  return val;
}


/* Find a good as possible size for the hash table so that all the
   non-zero entries in HASHCODES don't collide too much and the table
   isn't too large.  There is no exact formular for this so we use a
   heuristic.  Depending on the optimization level the search is
   longer or shorter.  */
static size_t
optimal_bucket_size (Elf32_Word *hashcodes, size_t maxcnt, int optlevel)
{
  size_t minsize;
  size_t maxsize;
  size_t bestsize;
  uint64_t bestcost;
  size_t size;
  uint32_t *counts;
  uint32_t *lengths;

  if (maxcnt == 0)
    return 0;

  /* When we are not optimizing we run only very few tests.  */
  if (optlevel <= 0)
    {
      minsize = maxcnt;
      maxsize = maxcnt + 10000 / maxcnt;
    }
  else
    {
      /* Does not make much sense to start with a smaller table than
       one which has at least four collisions.  */
      minsize = MAX (1, maxcnt / 4);
      /* We look for a best fit in the range of up to eigth times the
       number of elements.  */
      maxsize = 2 * maxcnt + (6 * MIN (optlevel, 100) * maxcnt) / 100;
    }
  bestsize = maxcnt;
  bestcost = UINT_MAX;

  /* Array for counting the collisions and chain lengths.  */
  counts = (uint32_t *) xmalloc ((maxcnt + 1 + maxsize) * sizeof (uint32_t));
  lengths = &counts[maxcnt + 1];

  for (size = minsize; size <= maxsize; ++size)
    {
      size_t inner;
      uint64_t cost;
      uint32_t maxlength;
      uint64_t success;
      uint32_t acc;
      double factor;

      memset (lengths, '\0', size * sizeof (uint32_t));
      memset (counts, '\0', (maxcnt + 1) * sizeof (uint32_t));

      /* Determine how often each hash bucket is used.  */
      for (inner = 0; inner < maxcnt; ++inner)
      ++lengths[hashcodes[inner] % size];

      /* Determine the lengths.  */
      maxlength = 0;
      for (inner = 0; inner < size; ++inner)
      {
        ++counts[lengths[inner]];

        if (lengths[inner] > maxlength)
          maxlength = lengths[inner];
      }

      /* Determine successful lookup length.  */
      acc = 0;
      success = 0;
      for (inner = 0; inner <= maxlength; ++inner)
      {
        acc += inner;
        success += counts[inner] * acc;
      }

      /* We can compute two factors now: the average length of a
       positive search and the average length of a negative search.
       We count the number of comparisons which have to look at the
       names themselves.  Recognizing that the chain ended is not
       accounted for since it's almost for free.

       Which lookup is more important depends on the kind of DSO.
       If it is a system DSO like libc it is expected that most
       lookups succeed.  Otherwise most lookups fail.  */
      if (ld_state.is_system_library)
      factor = (1.0 * (double) success / (double) maxcnt
              + 0.3 * (double) maxcnt / (double) size);
      else
      factor = (0.3 * (double) success / (double) maxcnt
              + 1.0 * (double) maxcnt / (double) size);

      /* Combine the lookup cost factor.  The 1/16th addend adds
       penalties for too large table sizes.  */
      cost = (2 + maxcnt + size) * (factor + 1.0 / 16.0);

#if 0
      printf ("maxcnt = %d, size = %d, cost = %Ld, success = %g, fail = %g, factor = %g\n",
            maxcnt, size, cost, (double) success / (double) maxcnt, (double) maxcnt / (double) size, factor);
#endif

      /* Compare with current best results.  */
      if (cost < bestcost)
      {
        bestcost = cost;
        bestsize = size;
      }
    }

  free (counts);

  return bestsize;
}


static XElf_Addr
find_entry_point (void)
{
  XElf_Addr result;

  if (ld_state.entry != NULL)
    {
      struct symbol search = { .name = ld_state.entry };
      struct symbol *syment;

      syment = ld_symbol_tab_find (&ld_state.symbol_tab,
                           elf_hash (ld_state.entry), &search);
      if (syment != NULL && syment->defined)
      {
        /* We found the symbol.  */
        Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf,
                                        ld_state.symscnidx), NULL);

        XElf_Sym_vardef (sym);

        sym = NULL;
        if (data != NULL)
          xelf_getsym (data, ld_state.dblindirect[syment->outsymidx], sym);

        if (sym == NULL && ld_state.need_dynsym && syment->outdynsymidx != 0)
          {
            /* Use the dynamic symbol table if available.  */
            data = elf_getdata (elf_getscn (ld_state.outelf,
                                    ld_state.dynsymscnidx), NULL);

            sym = NULL;
            if (data != NULL)
            xelf_getsym (data, syment->outdynsymidx, sym);
          }

        if (sym != NULL)
          return sym->st_value;

        /* XXX What to do if the output has no non-dynamic symbol
           table and the dynamic symbol table does not contain the
           symbol?  */
        assert (ld_state.need_symtab);
        assert (ld_state.symscnidx != 0);
      }
    }

  /* We couldn't find the symbol or none was given.  Use the first
     address of the ".text" section then.  */


  result = 0;

  /* In DSOs this is no fatal error.  They usually have no entry
     points.  In this case we set the entry point to zero, which makes
     sure it will always fail.  */
  if (ld_state.file_type == executable_file_type)
    {
      if (ld_state.entry != NULL)
      error (0, 0, gettext ("\
cannot find entry symbol '%s': defaulting to %#0*" PRIx64),
             ld_state.entry,
             xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18,
             (uint64_t) result);
      else
      error (0, 0, gettext ("\
no entry symbol specified: defaulting to %#0*" PRIx64),
             xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18,
             (uint64_t) result);
    }

  return result;
}


static void
fillin_special_symbol (struct symbol *symst, size_t scnidx, size_t nsym,
                   Elf_Data *symdata, struct Ebl_Strtab *strtab)
{
  assert (ld_state.file_type != relocatable_file_type);

  XElf_Sym_vardef (sym);
  xelf_getsym_ptr (symdata, nsym, sym);

  /* The name offset will be filled in later.  */
  sym->st_name = 0;
  /* Traditionally: globally visible.  */
  sym->st_info = XELF_ST_INFO (symst->local ? STB_LOCAL : STB_GLOBAL,
                         symst->type);
  sym->st_other = symst->hidden ? STV_HIDDEN : STV_DEFAULT;
  /* Reference to the GOT or dynamic section.  Since the GOT and
     dynamic section are only created for executables and DSOs it
     cannot be that the section index is too large.  */
  assert (scnidx != 0);
  assert (scnidx < SHN_LORESERVE || scnidx == SHN_ABS);
  sym->st_shndx = scnidx;
  /* We want the beginning of the section.  */
  sym->st_value = 0;

  /* Determine the size of the section.  */
  if (scnidx != SHN_ABS)
    {
      Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, scnidx),
                            NULL);
      assert (data != NULL);
      sym->st_size = data->d_size;
      /* Make sure there is no second data block.  */
      assert (elf_getdata (elf_getscn (ld_state.outelf, scnidx), data)
            == NULL);
    }

  /* Insert symbol into the symbol table.  Note that we do not have to
     use xelf_update_symshdx.  */
  (void) xelf_update_sym (symdata, nsym, sym);

  /* Cross-references.  */
  ndxtosym[nsym] = symst;
  symst->outsymidx = nsym;

  /* Add the name to the string table.  */
  symstrent[nsym] = ebl_strtabadd (strtab, symst->name, 0);
}


static void
new_dynamic_entry (Elf_Data *data, int idx, XElf_Sxword tag, XElf_Addr val)
{
  XElf_Dyn_vardef (dyn);
  xelf_getdyn_ptr (data, idx, dyn);
  dyn->d_tag = tag;
  dyn->d_un.d_ptr = val;
  (void) xelf_update_dyn (data, idx, dyn);
}


static void
allocate_version_names (struct usedfiles *runp, struct Ebl_Strtab *dynstrtab)
{
  /* If this DSO has no versions skip it.  */
  if (runp->status != opened || runp->verdefdata == NULL)
    return;

  /* Add the object name.  */
  int offset = 0;
  while (1)
    {
      XElf_Verdef_vardef (def);
      XElf_Verdaux_vardef (aux);

      /* Get data at the next offset.  */
      xelf_getverdef (runp->verdefdata, offset, def);
      assert (def != NULL);
      xelf_getverdaux (runp->verdefdata, offset + def->vd_aux, aux);
      assert (aux != NULL);

      assert (def->vd_ndx <= runp->nverdef);
      if (def->vd_ndx == 1 || runp->verdefused[def->vd_ndx] != 0)
      {
        runp->verdefent[def->vd_ndx]
          = ebl_strtabadd (dynstrtab, elf_strptr (runp->elf,
                                        runp->dynsymstridx,
                                        aux->vda_name), 0);

        if (def->vd_ndx > 1)
          runp->verdefused[def->vd_ndx] = ld_state.nextveridx++;
      }

      if (def->vd_next == 0)
      /* That were all versions.  */
      break;

      offset += def->vd_next;
    }
}


static XElf_Off
create_verneed_data (XElf_Off offset, Elf_Data *verneeddata,
                 struct usedfiles *runp, int *ntotal)
{
  size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1);
  size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1);
  int need_offset;
  bool filled = false;
  GElf_Verneed verneed;
  GElf_Vernaux vernaux;
  int ndef = 0;
  size_t cnt;

  /* If this DSO has no versions skip it.  */
  if (runp->nverdefused == 0)
    return offset;

  /* We fill in the Verneed record last.  Remember the offset.  */
  need_offset = offset;
  offset += verneed_size;

  for (cnt = 2; cnt <= runp->nverdef; ++cnt)
    if (runp->verdefused[cnt] != 0)
      {
      assert (runp->verdefent[cnt] != NULL);

      if (filled)
        {
          vernaux.vna_next = vernaux_size;
          (void) gelf_update_vernaux (verneeddata, offset, &vernaux);
          offset += vernaux_size;
        }

      vernaux.vna_hash = elf_hash (ebl_string (runp->verdefent[cnt]));
      vernaux.vna_flags = 0;
      vernaux.vna_other = runp->verdefused[cnt];
      vernaux.vna_name = ebl_strtaboffset (runp->verdefent[cnt]);
      filled = true;
      ++ndef;
      }

  assert (filled);
  vernaux.vna_next = 0;
  (void) gelf_update_vernaux (verneeddata, offset, &vernaux);
  offset += vernaux_size;

  verneed.vn_version = VER_NEED_CURRENT;
  verneed.vn_cnt = ndef;
  verneed.vn_file = ebl_strtaboffset (runp->verdefent[1]);
  /* The first auxiliary entry is always found directly
     after the verneed entry.  */
  verneed.vn_aux = verneed_size;
  verneed.vn_next = --*ntotal > 0 ? offset - need_offset : 0;
  (void) gelf_update_verneed (verneeddata, need_offset, &verneed);

  return offset;
}


/* Create the output file.

   For relocatable files what basically has to happen is that all
   sections from all input files are written into the output file.
   Sections with the same name are combined (offsets adjusted
   accordingly).  The symbol tables are combined in one single table.
   When stripping certain symbol table entries are omitted.

   For executables (shared or not) we have to create the program header,
   additional sections like the .interp, eventually (in addition) create
   a dynamic symbol table and a dynamic section.  Also the relocations
   have to be processed differently.  */
static int
ld_generic_create_outfile (struct ld_state *statep)
{
  struct scnlist
  {
    size_t scnidx;
    struct scninfo *scninfo;
    struct scnlist *next;
  };
  struct scnlist *rellist = NULL;
  size_t cnt;
  Elf_Scn *symscn = NULL;
  Elf_Scn *xndxscn = NULL;
  Elf_Scn *strscn = NULL;
  struct Ebl_Strtab *strtab = NULL;
  struct Ebl_Strtab *dynstrtab = NULL;
  XElf_Shdr_vardef (shdr);
  Elf_Data *data;
  Elf_Data *symdata = NULL;
  Elf_Data *xndxdata = NULL;
  struct usedfiles *file;
  size_t nsym;
  size_t nsym_local;
  size_t nsym_allocated;
  size_t nsym_dyn = 0;
  Elf32_Word *dblindirect = NULL;
#ifndef NDEBUG
  bool need_xndx;
#endif
  Elf_Scn *shstrtab_scn;
  size_t shstrtab_ndx;
  XElf_Ehdr_vardef (ehdr);
  struct Ebl_Strent *symtab_ent = NULL;
  struct Ebl_Strent *xndx_ent = NULL;
  struct Ebl_Strent *strtab_ent = NULL;
  struct Ebl_Strent *shstrtab_ent;
  struct scngroup *groups;
  Elf_Scn *dynsymscn = NULL;
  Elf_Data *dynsymdata = NULL;
  Elf_Data *dynstrdata = NULL;
  Elf32_Word *hashcodes = NULL;
  size_t nsym_dyn_allocated = 0;
  Elf_Scn *versymscn = NULL;
  Elf_Data *versymdata = NULL;

  if (ld_state.need_symtab)
    {
      /* First create the symbol table.  We need the symbol section itself
       and the string table for it.  */
      symscn = elf_newscn (ld_state.outelf);
      ld_state.symscnidx = elf_ndxscn (symscn);
      symdata = elf_newdata (symscn);
      if (symdata == NULL)
      error (EXIT_FAILURE, 0,
             gettext ("cannot create symbol table for output file: %s"),
             elf_errmsg (-1));

      symdata->d_type = ELF_T_SYM;
      /* This is an estimated size, but it will definitely cap the real value.
       We might have to adjust the number later.  */
      nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot
                  + ld_state.nusedsections + ld_state.nlscript_syms);
      symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM,
                            nsym_allocated);

      /* Optionally the extended section table.  */
      /* XXX Is SHN_LORESERVE correct?  Do we need some other sections?  */
      if (unlikely (ld_state.nusedsections >= SHN_LORESERVE))
      {
        xndxscn = elf_newscn (ld_state.outelf);
        ld_state.xndxscnidx = elf_ndxscn (xndxscn);

        xndxdata = elf_newdata (xndxscn);
        if (xndxdata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create symbol table for output file: %s"),
               elf_errmsg (-1));

        /* The following relies on the fact that Elf32_Word and Elf64_Word
           have the same size.  */
        xndxdata->d_type = ELF_T_WORD;
        /* This is an estimated size, but it will definitely cap the
           real value.  we might have to adjust the number later.  */
        xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD,
                               nsym_allocated);
        /* The first entry is left empty, clear it here and now.  */
        xndxdata->d_buf = memset (xmalloc (xndxdata->d_size), '\0',
                            xelf_fsize (ld_state.outelf, ELF_T_WORD,
                                    1));
        xndxdata->d_off = 0;
        /* XXX Should use an ebl function.  */
        xndxdata->d_align = sizeof (Elf32_Word);
      }
    }
  else
    {
      assert (ld_state.need_dynsym);

      /* First create the symbol table.  We need the symbol section itself
       and the string table for it.  */
      symscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx);
      symdata = elf_newdata (symscn);
      if (symdata == NULL)
      error (EXIT_FAILURE, 0,
             gettext ("cannot create symbol table for output file: %s"),
             elf_errmsg (-1));

      symdata->d_version = EV_CURRENT;
      symdata->d_type = ELF_T_SYM;
      /* This is an estimated size, but it will definitely cap the real value.
       We might have to adjust the number later.  */
      nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot
                  - ld_state.nlocalsymbols + ld_state.nlscript_syms);
      symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM,
                            nsym_allocated);
    }

  /* The first entry is left empty, clear it here and now.  */
  symdata->d_buf = memset (xmalloc (symdata->d_size), '\0',
                     xelf_fsize (ld_state.outelf, ELF_T_SYM, 1));
  symdata->d_off = 0;
  /* XXX This is ugly but how else can it be done.  */
  symdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);

  /* Allocate another array to keep track of the handles for the symbol
     names.  */
  symstrent = (struct Ebl_Strent **) xcalloc (nsym_allocated,
                                    sizeof (struct Ebl_Strent *));

  /* By starting at 1 we effectively add a null entry.  */
  nsym = 1;

  /* Iteration over all sections.  */
  for (cnt = 0; cnt < ld_state.nallsections; ++cnt)
    {
      struct scnhead *head = ld_state.allsections[cnt];
      Elf_Scn *scn;
      struct scninfo *runp;
      XElf_Off offset;
      Elf32_Word xndx;

      /* Don't handle unused sections at all.  */
      if (!head->used)
      continue;

      /* Get the section handle.  */
      scn = elf_getscn (ld_state.outelf, head->scnidx);

      if (unlikely (head->kind == scn_dot_interp))
      {
        Elf_Data *outdata = elf_newdata (scn);
        if (outdata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create section for output file: %s"),
               elf_errmsg (-1));

        /* This is the string we'll put in the section.  */
        const char *interp = ld_state.interp ?: "/lib/ld.so.1";

        /* Create the section data.  */
        outdata->d_buf = (void *) interp;
        outdata->d_size = strlen (interp) + 1;
        outdata->d_type = ELF_T_BYTE;
        outdata->d_off = 0;
        outdata->d_align = 1;
        outdata->d_version = EV_CURRENT;

        /* Remember the index of this section.  */
        ld_state.interpscnidx = head->scnidx;

        continue;
      }

      if (unlikely (head->kind == scn_dot_got))
      {
        /* Remember the index of this section.  */
        ld_state.gotscnidx = elf_ndxscn (scn);

        /* Give the backend the change to initialize the section.  */
        INITIALIZE_GOT (&ld_state, scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_dynrel))
      {
        Elf_Data *outdata;

        outdata = elf_newdata (scn);
        if (outdata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create section for output file: %s"),
               elf_errmsg (-1));

        outdata->d_size = ld_state.relsize_total;
        outdata->d_buf = xmalloc (outdata->d_size);
        outdata->d_type = (REL_TYPE (&ld_state) == DT_REL
                       ? ELF_T_REL : ELF_T_RELA);
        outdata->d_off = 0;
        outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);

        /* Remember the index of this section.  */
        ld_state.reldynscnidx = elf_ndxscn (scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_dynamic))
      {
        /* Only create the data for now.  */
        Elf_Data *outdata;

        /* Account for a few more entries we have to add.  */
        if (ld_state.dt_flags != 0)
          ++ld_state.ndynamic;
        if (ld_state.dt_flags_1 != 0)
          ++ld_state.ndynamic;
        if (ld_state.dt_feature_1 != 0)
          ++ld_state.ndynamic;

        outdata = elf_newdata (scn);
        if (outdata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create section for output file: %s"),
               elf_errmsg (-1));

        /* Create the section data.  */
        outdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_DYN,
                              ld_state.ndynamic);
        outdata->d_buf = xcalloc (1, outdata->d_size);
        outdata->d_type = ELF_T_DYN;
        outdata->d_off = 0;
        outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);

        /* Remember the index of this section.  */
        ld_state.dynamicscnidx = elf_ndxscn (scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_dynsym))
      {
        /* We already know the section index.  */
        assert (ld_state.dynsymscnidx == elf_ndxscn (scn));

        continue;
      }

      if (unlikely (head->kind == scn_dot_dynstr))
      {
        /* Remember the index of this section.  */
        ld_state.dynstrscnidx = elf_ndxscn (scn);

        /* Create the string table.  */
        dynstrtab = ebl_strtabinit (true);

        /* XXX TBI
           We have to add all the strings which are needed in the
           dynamic section here.  This means DT_FILTER,
           DT_AUXILIARY, ... entries.  */
        if (ld_state.ndsofiles > 0)
          {
            struct usedfiles *frunp = ld_state.dsofiles;

            do
            if (! frunp->as_needed || frunp->used)
              frunp->sonameent = ebl_strtabadd (dynstrtab, frunp->soname,
                                        0);
            while ((frunp = frunp->next) != ld_state.dsofiles);
          }


        /* Add the runtime path information.  The strings are stored
           in the .dynstr section.  If both rpath and runpath are defined
           the runpath information is used.  */
        if (ld_state.runpath != NULL || ld_state.rpath != NULL)
          {
            struct pathelement *startp;
            struct pathelement *prunp;
            int tag;
            size_t len;
            char *str;
            char *cp;

            if (ld_state.runpath != NULL)
            {
              startp = ld_state.runpath;
              tag = DT_RUNPATH;
            }
            else
            {
              startp = ld_state.rpath;
              tag = DT_RPATH;
            }

            /* Determine how long the string will be.  */
            for (len = 0, prunp = startp; prunp != NULL; prunp = prunp->next)
            len += strlen (prunp->pname) + 1;

            cp = str = (char *) obstack_alloc (&ld_state.smem, len);
            /* Copy the string.  */
            for (prunp = startp; prunp != NULL; prunp = prunp->next)
            {
              cp = stpcpy (cp, prunp->pname);
              *cp++ = ':';
            }
            /* Remove the last colon.  */
            cp[-1] = '\0';

            /* Remember the values until we can generate the dynamic
             section.  */
            ld_state.rxxpath_strent = ebl_strtabadd (dynstrtab, str, len);
            ld_state.rxxpath_tag = tag;
          }

        continue;
      }

      if (unlikely (head->kind == scn_dot_hash))
      {
        /* Remember the index of this section.  */
        ld_state.hashscnidx = elf_ndxscn (scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_plt))
      {
        /* Remember the index of this section.  */
        ld_state.pltscnidx = elf_ndxscn (scn);

        /* Give the backend the change to initialize the section.  */
        INITIALIZE_PLT (&ld_state, scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_pltrel))
      {
        /* Remember the index of this section.  */
        ld_state.pltrelscnidx = elf_ndxscn (scn);

        /* Give the backend the change to initialize the section.  */
        INITIALIZE_PLTREL (&ld_state, scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_version))
      {
        /* Remember the index of this section.  */
        ld_state.versymscnidx = elf_ndxscn (scn);

        continue;
      }

      if (unlikely (head->kind == scn_dot_version_r))
      {
        /* Remember the index of this section.  */
        ld_state.verneedscnidx = elf_ndxscn (scn);

        continue;
      }

      /* If we come here we must be handling a normal section.  */
      assert (head->kind == scn_normal);

      /* Create an STT_SECTION entry in the symbol table.  But not for
       the symbolic symbol table.  */
      if (ld_state.need_symtab)
      {
        /* XXX Can we be cleverer and do this only if needed?  */
        XElf_Sym_vardef (sym);

        /* Optimization ahead: in the native linker we get a pointer
           to the final location so that the following code writes
           directly in the correct place.  Otherwise we write into
           the local variable first.  */
        xelf_getsym_ptr (symdata, nsym, sym);

        /* Usual section symbol: local, no specific information,
           except the section index.  The offset here is zero, the
           start address will later be added.  */
        sym->st_name = 0;
        sym->st_info = XELF_ST_INFO (STB_LOCAL, STT_SECTION);
        sym->st_other = 0;
        sym->st_value = 0;
        sym->st_size = 0;
        /* In relocatable files the section index can be too big for
           the ElfXX_Sym struct.  we have to deal with the extended
           symbol table.  */
        if (likely (head->scnidx < SHN_LORESERVE))
          {
            sym->st_shndx = head->scnidx;
            xndx = 0;
          }
        else
          {
            sym->st_shndx = SHN_XINDEX;
            xndx = head->scnidx;
          }
        /* Commit the change.  See the optimization above, this does
           not change the symbol table entry.  But the extended
           section index table entry is always written, if there is
           such a table.  */
        assert (nsym < nsym_allocated);
        xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0);

        /* Remember the symbol's index in the symbol table.  */
        head->scnsymidx = nsym++;
      }

      if (head->type == SHT_REL || head->type == SHT_RELA)
      {
        /* Remember that we have to fill in the symbol table section
           index.  */
        if (ld_state.file_type == relocatable_file_type)
          {
            struct scnlist *newp;

            newp = (struct scnlist *) alloca (sizeof (*newp));
            newp->scnidx = head->scnidx;
            newp->scninfo = head->last->next;
#ifndef NDEBUG
            newp->next = NULL;
#endif
            SNGL_LIST_PUSH (rellist, newp);
          }
        else
          {
            /* When we create an executable or a DSO we don't simply
             copy the existing relocations.  Instead many will be
             resolved, others will be converted.  Create a data buffer
             large enough to contain the contents which we will fill
             in later.  */
            int type = head->type == SHT_REL ? ELF_T_REL : ELF_T_RELA;

            data = elf_newdata (scn);
            if (data == NULL)
            error (EXIT_FAILURE, 0,
                   gettext ("cannot create section for output file: %s"),
                   elf_errmsg (-1));

            data->d_size = xelf_fsize (ld_state.outelf, type, head->relsize);
            data->d_buf = xcalloc (data->d_size, 1);
            data->d_type = type;
            data->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);
            data->d_off = 0;

            continue;
          }
      }

      /* Recognize string and merge flag and handle them.  */
      if (head->flags & SHF_MERGE)
      {
        /* We merge the contents of the sections.  For this we do
           not look at the contents of section directly.  Instead we
           look at the symbols of the section.  */
        Elf_Data *outdata;

        /* Concatenate the lists of symbols for all sections.

           XXX In case any input section has no symbols associated
           (this happens for debug sections) we cannot use this
           method.  Implement parsing the other debug sections and
           find the string pointers.  For now we don't merge.  */
        runp = head->last->next;
        if (runp->symbols == NULL)
          {
            head->flags &= ~SHF_MERGE;
            goto no_merge;
          }
        head->symbols = runp->symbols;

        while ((runp = runp->next) != head->last->next)
          {
            if (runp->symbols == NULL)
            {
              head->flags &= ~SHF_MERGE;
              head->symbols = NULL;
              goto no_merge;
            }

            struct symbol *oldhead = head->symbols->next_in_scn;

            head->symbols->next_in_scn = runp->symbols->next_in_scn;
            runp->symbols->next_in_scn = oldhead;
            head->symbols = runp->symbols;
          }

        /* Create the output section.  */
        outdata = elf_newdata (scn);
        if (outdata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create section for output file: %s"),
               elf_errmsg (-1));

        /* We use different merging algorithms for performance
           reasons.  We can easily handle single-byte and
           wchar_t-wide character strings.  All other cases (which
           really should happen in real life) are handled by the
           generic code.  */
        if (SCNINFO_SHDR (head->last->shdr).sh_entsize == 1
            && (head->flags & SHF_STRINGS))
          {
            /* Simple, single-byte string matching.  */
            struct Ebl_Strtab *mergestrtab;
            struct symbol *symrunp;
            Elf_Data *locsymdata = NULL;
            Elf_Data *locdata = NULL;

            mergestrtab = ebl_strtabinit (false);

            symrunp = head->symbols->next_in_scn;
            file = NULL;
            do
            {
              /* Accelarate the loop.  We cache the file
                 information since it might very well be the case
                 that the previous entry was from the same
                 file.  */
              if (symrunp->file != file)
                {
                  /* Remember the file.  */
                  file = symrunp->file;
                  /* Symbol table data from that file.  */
                  locsymdata = file->symtabdata;
                  /* String section data.  */
                  locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn,
                                   NULL);
                  assert (locdata != NULL);
                  /* While we are at it, remember the output
                   section.  If we don't access the string data
                   section the section won't be in the output
                   file.  So it is sufficient to do the work
                   here.  */
                  file->scninfo[symrunp->scndx].outscnndx = head->scnidx;
                }

              /* Get the symbol information.  This provides us the
                 offset into the string data section.  */
              XElf_Sym_vardef (sym);
              xelf_getsym (locsymdata, symrunp->symidx, sym);
              assert (sym != NULL);

              /* Get the data from the file.  Note that we access
                 the raw section data; no endian-ness issues with
                 single-byte strings.  */
              symrunp->merge.handle
                = ebl_strtabadd (mergestrtab,
                             (char *) locdata->d_buf + sym->st_value,
                             0);
            }
            while ((symrunp = symrunp->next_in_scn)
                 != head->symbols->next_in_scn);

            /* All strings have been added.  Create the final table.  */
            ebl_strtabfinalize (mergestrtab, outdata);

            /* Compute the final offsets in the section.  */
            symrunp = runp->symbols;
            do
            {
              symrunp->merge.value
                = ebl_strtaboffset (symrunp->merge.handle);
              symrunp->merged = 1;
            }
            while ((symrunp = symrunp->next_in_scn) != runp->symbols);

            /* We don't need the string table anymore.  */
            ebl_strtabfree (mergestrtab);
          }
        else if (likely (SCNINFO_SHDR (head->last->shdr).sh_entsize
                     == sizeof (wchar_t))
               && likely (head->flags & SHF_STRINGS))
          {
            /* Simple, wchar_t string merging.  */
            struct Ebl_WStrtab *mergestrtab;
            struct symbol *symrunp;
            Elf_Data *locsymdata = NULL;
            Elf_Data *locdata = NULL;

            mergestrtab = ebl_wstrtabinit (false);

            symrunp = runp->symbols;
            file = NULL;
            do
            {
              /* Accelarate the loop.  We cache the file
                 information since it might very well be the case
                 that the previous entry was from the same
                 file.  */
              if (symrunp->file != file)
                {
                  /* Remember the file.  */
                  file = symrunp->file;
                  /* Symbol table data from that file.  */
                  locsymdata = file->symtabdata;
                  /* String section data.  */
                  locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn,
                                   NULL);
                  assert (locdata != NULL);

                  /* While we are at it, remember the output
                   section.  If we don't access the string data
                   section the section won't be in the output
                   file.  So it is sufficient to do the work
                   here.  */
                  file->scninfo[symrunp->scndx].outscnndx = head->scnidx;
                }

              /* Get the symbol information.  This provides us the
                 offset into the string data section.  */
              XElf_Sym_vardef (sym);
              xelf_getsym (locsymdata, symrunp->symidx, sym);
              assert (sym != NULL);

              /* Get the data from the file.  Using the raw
                 section data here is possible since we don't
                 interpret the string themselves except for
                 looking for the wide NUL character.  The NUL
                 character has fortunately the same representation
                 regardless of the byte order.  */
              symrunp->merge.handle
                = ebl_wstrtabadd (mergestrtab,
                              (wchar_t *) ((char *) locdata->d_buf
                                       + sym->st_value), 0);
            }
            while ((symrunp = symrunp->next_in_scn) != runp->symbols);

            /* All strings have been added.  Create the final table.  */
            ebl_wstrtabfinalize (mergestrtab, outdata);

            /* Compute the final offsets in the section.  */
            symrunp = runp->symbols;
            do
            {
              symrunp->merge.value
                = ebl_wstrtaboffset (symrunp->merge.handle);
              symrunp->merged = 1;
            }
            while ((symrunp = symrunp->next_in_scn) != runp->symbols);

            /* We don't need the string table anymore.  */
            ebl_wstrtabfree (mergestrtab);
          }
        else
          {
            /* Non-standard merging.  */
            struct Ebl_GStrtab *mergestrtab;
            struct symbol *symrunp;
            Elf_Data *locsymdata = NULL;
            Elf_Data *locdata = NULL;
            /* If this is no string section the length of each "string"
             is always one.  */
            unsigned int len = (head->flags & SHF_STRINGS) ? 0 : 1;

            /* This is the generic string table functionality.  Much
             slower than the specialized code.  */
            mergestrtab
            = ebl_gstrtabinit (SCNINFO_SHDR (head->last->shdr).sh_entsize,
                           false);

            symrunp = runp->symbols;
            file = NULL;
            do
            {
              /* Accelarate the loop.  We cache the file
                 information since it might very well be the case
                 that the previous entry was from the same
                 file.  */
              if (symrunp->file != file)
                {
                  /* Remember the file.  */
                  file = symrunp->file;
                  /* Symbol table data from that file.  */
                  locsymdata = file->symtabdata;
                  /* String section data.  */
                  locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn,
                                   NULL);
                  assert (locdata != NULL);

                  /* While we are at it, remember the output
                   section.  If we don't access the string data
                   section the section won't be in the output
                   file.  So it is sufficient to do the work
                   here.  */
                  file->scninfo[symrunp->scndx].outscnndx = head->scnidx;
                }

              /* Get the symbol information.  This provides us the
                 offset into the string data section.  */
              XElf_Sym_vardef (sym);
              xelf_getsym (locsymdata, symrunp->symidx, sym);
              assert (sym != NULL);

              /* Get the data from the file.  Using the raw
                 section data here is possible since we don't
                 interpret the string themselves except for
                 looking for the wide NUL character.  The NUL
                 character has fortunately the same representation
                 regardless of the byte order.  */
              symrunp->merge.handle
                = ebl_gstrtabadd (mergestrtab,
                              (char *) locdata->d_buf + sym->st_value,
                              len);
            }
            while ((symrunp = symrunp->next_in_scn) != runp->symbols);

            /* Create the final table.  */
            ebl_gstrtabfinalize (mergestrtab, outdata);

            /* Compute the final offsets in the section.  */
            symrunp = runp->symbols;
            do
            {
              symrunp->merge.value
                = ebl_gstrtaboffset (symrunp->merge.handle);
              symrunp->merged = 1;
            }
            while ((symrunp = symrunp->next_in_scn) != runp->symbols);

            /* We don't need the string table anymore.  */
            ebl_gstrtabfree (mergestrtab);
          }
      }
      else
      {
      no_merge:
        assert (head->scnidx == elf_ndxscn (scn));

        /* It is important to start with the first list entry (and
           not just any one) to add the sections in the correct
           order.  */
        runp = head->last->next;
        offset = 0;
        do
          {
            Elf_Data *outdata = elf_newdata (scn);
            if (outdata == NULL)
            error (EXIT_FAILURE, 0,
                   gettext ("cannot create section for output file: %s"),
                   elf_errmsg (-1));

            /* Exceptional case: if we synthesize a data block SCN
             is NULL and the sectio header info must be for a
             SHT_NOBITS block and the size and alignment are
             filled in.  */
            if (likely (runp->scn != NULL))
            {
              data = elf_getdata (runp->scn, NULL);
              assert (data != NULL);

              /* We reuse the data buffer in the input file.  */
              *outdata = *data;

              /* Given that we read the input file from disk we know there
                 cannot be another data part.  */
              assert (elf_getdata (runp->scn, data) == NULL);
            }
            else
            {
              /* Must be a NOBITS section.  */
              assert  (SCNINFO_SHDR (runp->shdr).sh_type == SHT_NOBITS);

              outdata->d_buf = NULL;      /* Not needed.  */
              outdata->d_type = ELF_T_BYTE;
              outdata->d_version = EV_CURRENT;
              outdata->d_size = SCNINFO_SHDR (runp->shdr).sh_size;
              outdata->d_align = SCNINFO_SHDR (runp->shdr).sh_addralign;
            }

            XElf_Off align =  MAX (1, outdata->d_align);
            assert (powerof2 (align));
            offset = ((offset + align - 1) & ~(align - 1));

            runp->offset = offset;
            runp->outscnndx = head->scnidx;
            runp->allsectionsidx = cnt;

            outdata->d_off = offset;

            offset += outdata->d_size;
          }
        while ((runp = runp->next) != head->last->next);

        /* If necessary add the additional line to the .comment section.  */
        if (ld_state.add_ld_comment
            && head->flags == 0
            && head->type == SHT_PROGBITS
            && strcmp (head->name, ".comment") == 0
            && head->entsize == 0)
          {
            Elf_Data *outdata = elf_newdata (scn);

            if (outdata == NULL)
            error (EXIT_FAILURE, 0,
                   gettext ("cannot create section for output file: %s"),
                   elf_errmsg (-1));

            outdata->d_buf = (void *) "\0ld (Red Hat " PACKAGE ") " VERSION;
            outdata->d_size = strlen ((char *) outdata->d_buf + 1) + 2;
            outdata->d_off = offset;
            outdata->d_type = ELF_T_BYTE;
            outdata->d_align = 1;
          }
        /* XXX We should create a .comment section if none exists.
           This requires that we early on detect that no such
           section exists.  This should probably be implemented
           together with some merging of the section contents.
           Currently identical entries are not merged.  */
      }
    }

  /* The table we collect the strings in.  */
  strtab = ebl_strtabinit (true);
  if (strtab == NULL)
    error (EXIT_FAILURE, errno, gettext ("cannot create string table"));


#ifndef NDEBUG
  /* Keep track of the use of the XINDEX.  */
  need_xndx = false;
#endif

  /* We we generate a normal symbol table for an executable and the
     --export-dynamic option is not given, we need an extra table
     which keeps track of the symbol entry belonging to the symbol
     table entry.  Note that EXPORT_ALL_DYNAMIC is always set if we
     generate a DSO so we do not have to test this separately.  */
  ndxtosym = (struct symbol **) xcalloc (nsym_allocated,
                               sizeof (struct symbol));

  /* Create the special symbol for the GOT section.  */
  if (ld_state.got_symbol != NULL)
    {
      assert (nsym < nsym_allocated);
      fillin_special_symbol (ld_state.got_symbol, ld_state.gotscnidx,
                       nsym++, symdata, strtab);
    }

  /* Similarly for the dynamic section symbol.  */
  if (ld_state.dyn_symbol != NULL)
    {
      assert (nsym < nsym_allocated);
      fillin_special_symbol (ld_state.dyn_symbol, ld_state.dynamicscnidx,
                       nsym++, symdata, strtab);
    }

  /* Create symbol table entries for the symbols defined in the linker
     script.  */
  if (ld_state.lscript_syms != NULL)
    {
      struct symbol *rsym = ld_state.lscript_syms;
      do
      {
        assert (nsym < nsym_allocated);
        fillin_special_symbol (rsym, SHN_ABS, nsym++, symdata, strtab);
      }
      while ((rsym = rsym->next) != NULL);
    }

  /* Iterate over all input files to collect the symbols.  */
  file = ld_state.relfiles->next;
  symdata = elf_getdata (elf_getscn (ld_state.outelf, ld_state.symscnidx),
                   NULL);

  do
    {
      size_t maxcnt;
      Elf_Data *insymdata;
      Elf_Data *inxndxdata;

      /* There must be no dynamic symbol table when creating
       relocatable files.  */
      assert (ld_state.file_type != relocatable_file_type
            || file->dynsymtabdata == NULL);

      insymdata = file->symtabdata;
      assert (insymdata != NULL);
      inxndxdata = file->xndxdata;

      maxcnt = file->nsymtab;

      file->symindirect = (Elf32_Word *) xcalloc (maxcnt, sizeof (Elf32_Word));

      /* The dynamic symbol table does not contain local symbols.  So
         we skip those entries.  */
      for (cnt = ld_state.need_symtab ? 1 : file->nlocalsymbols; cnt < maxcnt;
         ++cnt)
      {
        XElf_Sym_vardef (sym);
        Elf32_Word xndx;
        struct symbol *defp = NULL;

        xelf_getsymshndx (insymdata, inxndxdata, cnt, sym, xndx);
        assert (sym != NULL);

        if (unlikely (XELF_ST_TYPE (sym->st_info) == STT_SECTION))
          {
            /* Section symbols should always be local but who knows...  */
            if (ld_state.need_symtab)
            {
              /* Determine the real section index in the source file.
                 Use the XINDEX section content if necessary.  We don't
                 add this information to the dynamic symbol table.  */
              if (sym->st_shndx != SHN_XINDEX)
                xndx = sym->st_shndx;

              assert (file->scninfo[xndx].allsectionsidx
                    < ld_state.nallsections);
              file->symindirect[cnt] = ld_state.allsections[file->scninfo[xndx].allsectionsidx]->scnsymidx;
              /* Note that the resulting index can be zero here.  There is
                 no guarantee that the output file will contain all the
                 sections the input file did.  */
            }
            continue;
          }

        if ((ld_state.strip >= strip_all || !ld_state.need_symtab)
            /* XXX Do we need these entries?  */
            && XELF_ST_TYPE (sym->st_info) == STT_FILE)
          continue;

#if NATIVE_ELF != 0
        /* Copy old data.  We create a temporary copy because the
           symbol might still be discarded.  */
        XElf_Sym sym_mem;
        sym_mem = *sym;
        sym = &sym_mem;
#endif

        if (sym->st_shndx != SHN_UNDEF
            && (sym->st_shndx < SHN_LORESERVE
              || sym->st_shndx == SHN_XINDEX))
          {
            /* If we are creating an executable with no normal
             symbol table and we do not export all symbols and
             this symbol is not defined in a DSO as well, ignore
             it.  */
            if (!ld_state.export_all_dynamic && !ld_state.need_symtab)
            {
              assert (cnt >= file->nlocalsymbols);
              defp = file->symref[cnt];
              assert (defp != NULL);

              if (!defp->in_dso)
                /* Ignore it.  */
                continue;
            }

            /* Determine the real section index in the source file.  Use
             the XINDEX section content if necessary.  */
            if (sym->st_shndx != SHN_XINDEX)
            xndx = sym->st_shndx;

            sym->st_value += file->scninfo[xndx].offset;

            assert (file->scninfo[xndx].outscnndx < SHN_LORESERVE
                  || file->scninfo[xndx].outscnndx > SHN_HIRESERVE);
            if (unlikely (file->scninfo[xndx].outscnndx > SHN_LORESERVE))
            {
              /* It is not possible to have an extended section index
                 table for the dynamic symbol table.  */
              if (!ld_state.need_symtab)
                error (EXIT_FAILURE, 0, gettext ("\
section index too large in dynamic symbol table"));

              assert (xndxdata != NULL);
              sym->st_shndx = SHN_XINDEX;
              xndx = file->scninfo[xndx].outscnndx;
#ifndef NDEBUG
              need_xndx = true;
#endif
            }
            else
            {
              sym->st_shndx = file->scninfo[xndx].outscnndx;
              xndx = 0;
            }
          }
        else if (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_UNDEF)
          {
            /* Check whether we have a (real) definition for this
             symbol.  If this is the case we skip this symbol
             table entry.  */
            assert (cnt >= file->nlocalsymbols);
            defp = file->symref[cnt];
            assert (defp != NULL);

            assert (sym->st_shndx != SHN_COMMON || defp->defined);

            if ((sym->st_shndx == SHN_COMMON && !defp->common)
              || (sym->st_shndx == SHN_UNDEF && defp->defined)
              || defp->added)
            /* Ignore this symbol table entry, there is a
               "better" one or we already added it.  */
            continue;

            /* Remember that we already added this symbol.  */
            defp->added = 1;

            /* Adjust the section number for common symbols.  */
            if (sym->st_shndx == SHN_COMMON)
            {
              sym->st_value = (ld_state.common_section->offset
                           + file->symref[cnt]->merge.value);
              assert (ld_state.common_section->outscnndx < SHN_LORESERVE);
              sym->st_shndx = ld_state.common_section->outscnndx;
              xndx = 0;
            }
          }
        else if (unlikely (sym->st_shndx != SHN_ABS))
          {
            if (SPECIAL_SECTION_NUMBER_P (&ld_state, sym->st_shndx))
            /* XXX Add code to handle machine specific special
               sections.  */
            abort ();
          }

        /* Add the symbol name to the string table.  If the user
           chooses the highest level of stripping avoid adding names
           for local symbols in the string table.  */
        if (sym->st_name != 0
            && (ld_state.strip < strip_everything
              || XELF_ST_BIND (sym->st_info) != STB_LOCAL))
          symstrent[nsym] = ebl_strtabadd (strtab,
                                   elf_strptr (file->elf,
                                           file->symstridx,
                                           sym->st_name), 0);

        /* Once we know the name this field will get the correct
           offset.  For now set it to zero which means no name
           associated.  */
        GElf_Word st_name = sym->st_name;
        sym->st_name = 0;

        /* If we had to merge sections we have a completely new
           offset for the symbol.  */
        if (file->has_merge_sections && file->symref[cnt] != NULL
            && file->symref[cnt]->merged)
          sym->st_value = file->symref[cnt]->merge.value;

        /* Create the record in the output sections.  */
        assert (nsym < nsym_allocated);
        xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 1);

        /* Add the reference to the symbol record in case we need it.
           Find the symbol if this has not happened yet.  We do
           not need the information for local symbols.  */
        if (defp == NULL && cnt >= file->nlocalsymbols)
          {
            defp = file->symref[cnt];

            if (defp == NULL)
            {
              /* This is a symbol in a discarded COMDAT section.
                 Find the definition we actually use.  */
              // XXX The question is: do we have to do this here
              // XXX or can we do it earlier when we discard the
              // XXX section.
              struct symbol search;
              search.name = elf_strptr (file->elf, file->symstridx,
                                  st_name);
              struct symbol *realp
                = ld_symbol_tab_find (&ld_state.symbol_tab,
                                elf_hash (search.name), &search);
              if (realp == NULL)
                // XXX What to do here?
                error (EXIT_FAILURE, 0,
                     "couldn't find symbol from COMDAT section");

              file->symref[cnt] = realp;

              continue;
            }
          }

        /* Store the reference to the symbol record.  The sorting
           code will have to keep this array in the correct order, too.  */
        ndxtosym[nsym] = defp;

        /* One more entry finished.  */
        if (cnt >= file->nlocalsymbols)
          {
            assert (file->symref[cnt]->outsymidx == 0);
            file->symref[cnt]->outsymidx = nsym;
          }
        file->symindirect[cnt] = nsym++;
      }
    }
  while ((file = file->next) != ld_state.relfiles->next);
  /* Make sure we didn't create the extended section index table for
     nothing.  */
  assert (xndxdata == NULL || need_xndx);

  /* Create the version related sections.  */
  if (ld_state.verneedscnidx != 0)
    {
      /* We know the number of input files and total number of
       referenced versions.  This allows us to allocate the memory
       and then we iterate over the DSOs to get the version
       information.  */
      struct usedfiles *runp;

      runp = ld_state.dsofiles->next;
      do
      allocate_version_names (runp, dynstrtab);
      while ((runp = runp->next) != ld_state.dsofiles->next);

      if (ld_state.needed != NULL)
      {
        runp = ld_state.needed->next;
        do
          allocate_version_names (runp, dynstrtab);
        while ((runp = runp->next) != ld_state.needed->next);
      }
    }

  /* At this point we should hide symbols and so on.  */
  if (ld_state.default_bind_local || ld_state.version_str_tab.filled > 0)
    /* XXX Add one more test when handling of wildcard symbol names
       is supported.  */
    {
    /* Check all non-local symbols whether they are on the export list.  */
      bool any_reduced = false;

      for (cnt = 1; cnt < nsym; ++cnt)
      {
        XElf_Sym_vardef (sym);

        /* Note that we don't have to use 'xelf_getsymshndx' since we
           only need the binding and the symbol name.  */
        xelf_getsym (symdata, cnt, sym);
        assert (sym != NULL);

        if (reduce_symbol_p (sym, symstrent[cnt]))
          {
            sym->st_info = XELF_ST_INFO (STB_LOCAL,
                                 XELF_ST_TYPE (sym->st_info));
            (void) xelf_update_sym (symdata, cnt, sym);

            /* Show that we don't need this string anymore.  */
            if (ld_state.strip == strip_everything)
            {
              symstrent[cnt] = NULL;
              any_reduced = true;
            }
          }
      }

      if (unlikely (any_reduced))
      {
        /* Since we will not write names of local symbols in the
           output file and we have reduced the binding of some
           symbols the string table previously constructed contains
           too many string.  Correct it.  */
        struct Ebl_Strtab *newp = ebl_strtabinit (true);

        for (cnt = 1; cnt < nsym; ++cnt)
          if (symstrent[cnt] != NULL)
            symstrent[cnt] = ebl_strtabadd (newp,
                                    ebl_string (symstrent[cnt]), 0);

        ebl_strtabfree (strtab);
        strtab = newp;
      }
    }

  /* Add the references to DSOs.  We can add these entries this late
     (after sorting out versioning) because references to DSOs are not
     effected.  */
  if (ld_state.from_dso != NULL)
    {
      struct symbol *runp;
      size_t plt_base = nsym + ld_state.nfrom_dso - ld_state.nplt;
      size_t plt_idx = 0;
      size_t obj_idx = 0;

      assert (ld_state.nfrom_dso >= ld_state.nplt);
      runp = ld_state.from_dso;
      do
      {
        // XXX What about functions which are only referenced via
        // pointers and not PLT entries?  Can we distinguish such uses?
        size_t idx;
        if (runp->type == STT_FUNC)
          {
            /* Store the PLT entry number.  */
            runp->merge.value = plt_idx + 1;
            idx = plt_base + plt_idx++;
          }
        else
          idx = nsym + obj_idx++;

        XElf_Sym_vardef (sym);
        xelf_getsym_ptr (symdata, idx, sym);

        sym->st_value = 0;
        sym->st_size = runp->size;
        sym->st_info = XELF_ST_INFO (runp->weak ? STB_WEAK : STB_GLOBAL,
                               runp->type);
        sym->st_other = STV_DEFAULT;
        sym->st_shndx = SHN_UNDEF;

        /* Create the record in the output sections.  */
        xelf_update_symshndx (symdata, xndxdata, idx, sym, 0, 0);

        const char *name = runp->name;
        size_t namelen = 0;

        if (runp->file->verdefdata != NULL)
          {
            // XXX Is it useful to add the versym value to struct symbol?
            XElf_Versym versym;

            (void) xelf_getversym_copy (runp->file->versymdata, runp->symidx,
                                versym);

            /* One can only link with the default version.  */
            assert ((versym & 0x8000) == 0);

            const char *versname
            = ebl_string (runp->file->verdefent[versym]);

            size_t versname_len = strlen (versname) + 1;
            namelen = strlen (name) + versname_len + 2;
            char *newp = (char *) obstack_alloc (&ld_state.smem, namelen);
            memcpy (stpcpy (stpcpy (newp, name), "@@"),
                  versname, versname_len);
            name = newp;
          }

        symstrent[idx] = ebl_strtabadd (strtab, name, namelen);

        /* Record the initial index in the symbol table.  */
        runp->outsymidx = idx;

        /* Remember the symbol record this ELF symbol came from.  */
        ndxtosym[idx] = runp;
      }
      while ((runp = runp->next) != ld_state.from_dso);

      assert (nsym + obj_idx == plt_base);
      assert (plt_idx == ld_state.nplt);
      nsym = plt_base + plt_idx;
    }

  /* Now we know how many symbols will be in the output file.  Adjust
     the count in the section data.  */
  symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym);
  if (unlikely (xndxdata != NULL))
    xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, nsym);

  /* Create the symbol string table section.  */
  strscn = elf_newscn (ld_state.outelf);
  ld_state.strscnidx = elf_ndxscn (strscn);
  data = elf_newdata (strscn);
  xelf_getshdr (strscn, shdr);
  if (data == NULL || shdr == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section for output file: %s"),
         elf_errmsg (-1));

  /* Create a compact string table, allocate the memory for it, and
     fill in the section data information.  */
  ebl_strtabfinalize (strtab, data);

  shdr->sh_type = SHT_STRTAB;
  assert (shdr->sh_entsize == 0);

  if (unlikely (xelf_update_shdr (strscn, shdr) == 0))
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section for output file: %s"),
         elf_errmsg (-1));

  /* Fill in the offsets of the symbol names.  */
  for (cnt = 1; cnt < nsym; ++cnt)
    if (symstrent[cnt] != NULL)
      {
      XElf_Sym_vardef (sym);

      /* Note that we don't have to use 'xelf_getsymshndx' since we don't
         modify the section index.  */
      xelf_getsym (symdata, cnt, sym);
      /* This better worked, we did it before.  */
      assert (sym != NULL);
      sym->st_name = ebl_strtaboffset (symstrent[cnt]);
      (void) xelf_update_sym (symdata, cnt, sym);
      }

  /* Since we are going to reorder the symbol table but still have to
     be able to find the new position based on the old one (since the
     latter is stored in 'symindirect' information of the input file
     data structure) we have to create yet another indirection
     table.  */
  ld_state.dblindirect = dblindirect
    = (Elf32_Word *) xmalloc (nsym * sizeof (Elf32_Word));

  /* Sort the symbol table so that the local symbols come first.  */
  /* XXX We don't use stable sorting here.  It seems not necessary and
     would be more expensive.  If it turns out to be necessary this can
     be fixed easily.  */
  nsym_local = 1;
  cnt = nsym - 1;
  while (nsym_local < cnt)
    {
      XElf_Sym_vardef (locsym);
      Elf32_Word locxndx;
      XElf_Sym_vardef (globsym);
      Elf32_Word globxndx;

      do
      {
        xelf_getsymshndx (symdata, xndxdata, nsym_local, locsym, locxndx);
        /* This better works.  */
        assert (locsym != NULL);

        if (XELF_ST_BIND (locsym->st_info) != STB_LOCAL
            && (ld_state.need_symtab || ld_state.export_all_dynamic))
          {
            do
            {
              xelf_getsymshndx (symdata, xndxdata, cnt, globsym, globxndx);
              /* This better works.  */
              assert (globsym != NULL);

              if (unlikely (XELF_ST_BIND (globsym->st_info) == STB_LOCAL))
                {
                  /* We swap the two entries.  */
#if NATIVE_ELF != 0
                  /* Since we directly modify the data in the ELF
                   data structure we have to make a copy of one
                   of the entries.  */
                  XElf_Sym locsym_copy = *locsym;
                  locsym = &locsym_copy;
#endif
                  xelf_update_symshndx (symdata, xndxdata, nsym_local,
                                  globsym, globxndx, 1);
                  xelf_update_symshndx (symdata, xndxdata, cnt,
                                  locsym, locxndx, 1);

                  /* Also swap the cross references.  */
                  dblindirect[nsym_local] = cnt;
                  dblindirect[cnt] = nsym_local;

                  /* And the entries for the symbol names.  */
                  struct Ebl_Strent *strtmp = symstrent[nsym_local];
                  symstrent[nsym_local] = symstrent[cnt];
                  symstrent[cnt] = strtmp;

                  /* And the mapping from symbol table entry to
                   struct symbol record.  */
                  struct symbol *symtmp = ndxtosym[nsym_local];
                  ndxtosym[nsym_local] = ndxtosym[cnt];
                  ndxtosym[cnt] = symtmp;

                  /* Go to the next entry.  */
                  ++nsym_local;
                  --cnt;

                  break;
                }

              dblindirect[cnt] = cnt;
            }
            while (nsym_local < --cnt);

            break;
          }

        dblindirect[nsym_local] = nsym_local;
      }
      while (++nsym_local < cnt);
    }

  /* The symbol 'nsym_local' is currently pointing to might be local,
     too.  Check and increment the variable if this is the case.  */
  if (likely (nsym_local < nsym))
    {
      XElf_Sym_vardef (locsym);

      /* This entry isn't moved.  */
      dblindirect[nsym_local] = nsym_local;

      /* Note that it is OK to not use 'xelf_getsymshndx' here.  */
      xelf_getsym (symdata, nsym_local, locsym);
      /* This better works.  */
      assert (locsym != NULL);

      if (XELF_ST_BIND (locsym->st_info) == STB_LOCAL)
      ++nsym_local;
    }


  /* We need the versym array right away to keep track of the version
     symbols.  */
  if (ld_state.versymscnidx != 0)
    {
      /* We allocate more memory than we need since the array is morroring
       the dynamic symbol table and not the normal symbol table.  I.e.,
       no local symbols are present.  */
      versymscn = elf_getscn (ld_state.outelf, ld_state.versymscnidx);
      versymdata = elf_newdata (versymscn);
      if (versymdata == NULL)
      error (EXIT_FAILURE, 0,
             gettext ("cannot create versioning section: %s"),
             elf_errmsg (-1));

      versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF,
                               nsym - nsym_local + 1);
      versymdata->d_buf = xcalloc (1, versymdata->d_size);
      versymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_HALF, 1);
      versymdata->d_off = 0;
      versymdata->d_type = ELF_T_HALF;
    }


  /* If we have to construct the dynamic symbol table we must not include
     the local symbols.  If the normal symbol has to be emitted as well
     we haven't done anything else yet and we can construct it from
     scratch now.  */
  if (unlikely (!ld_state.need_symtab))
    {
      /* Note that the following code works even if there is no entry
       to remove since the zeroth entry is always local.  */
      size_t reduce = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_local - 1);

      XElf_Sym_vardef (nullsym);
      xelf_getsym_ptr (symdata, nsym_local - 1, nullsym);

      /* Note that we don't have to use 'xelf_update_symshndx' since
       this is the dynamic symbol table we write.  */
      (void) xelf_update_sym (symdata, nsym_local - 1,
                        memset (nullsym, '\0', sizeof (*nullsym)));

      /* Update the buffer pointer and size in the output data.  */
      symdata->d_buf = (char *) symdata->d_buf + reduce;
      symdata->d_size -= reduce;

      /* Add the version symbol information.  */
      if (versymdata != NULL)
      {
        nsym_dyn = 1;
        for (cnt = nsym_local; cnt < nsym; ++cnt, ++nsym_dyn)
          {
            struct symbol *symp = ndxtosym[cnt];

            if (symp->file->versymdata != NULL)
            {
              GElf_Versym versym;

              gelf_getversym (symp->file->versymdata, symp->symidx,
                          &versym);

              (void) gelf_update_versym (versymdata, nsym_dyn,
                                   &symp->file->verdefused[versym]);
            }
            }
      }

      /* Since we only created the dynamic symbol table the number of
       dynamic symbols is the total number of symbols.  */
      nsym_dyn = nsym - nsym_local + 1;

      /* XXX TBI.  Create whatever data structure is missing.  */
      abort ();
    }
  else if (ld_state.need_dynsym)
    {
      /* Create the dynamic symbol table section data along with the
       string table.  We look at all non-local symbols we found for
       the normal symbol table and add those.  */
      dynsymscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx);
      dynsymdata = elf_newdata (dynsymscn);

      dynstrdata = elf_newdata (elf_getscn (ld_state.outelf,
                                  ld_state.dynstrscnidx));
      if (dynsymdata == NULL || dynstrdata == NULL)
      error (EXIT_FAILURE, 0, gettext ("\
cannot create dynamic symbol table for output file: %s"),
             elf_errmsg (-1));

      nsym_dyn_allocated = nsym - nsym_local + 1;
      dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM,
                               nsym_dyn_allocated);
      dynsymdata->d_buf = memset (xmalloc (dynsymdata->d_size), '\0',
                          xelf_fsize (ld_state.outelf, ELF_T_SYM, 1));
      dynsymdata->d_type = ELF_T_SYM;
      dynsymdata->d_off = 0;
      dynsymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);

      /* We need one more array which contains the hash codes of the
       symbol names.  */
      hashcodes = (Elf32_Word *) xcalloc (nsym_dyn_allocated,
                                sizeof (Elf32_Word));

      /* We have and empty entry at the beginning.  */
      nsym_dyn = 1;

      /* We don't mix PLT symbols and others.  */
      size_t plt_idx = 1;
      size_t obj_idx = 1 + ld_state.nplt;

      /* Populate the table.  */
      for (cnt = nsym_local; cnt < nsym; ++cnt)
      {
        XElf_Sym_vardef (sym);

        xelf_getsym (symdata, cnt, sym);
        assert (sym != NULL);

        if (sym->st_shndx == SHN_XINDEX)
          error (EXIT_FAILURE, 0, gettext ("\
section index too large in dynamic symbol table"));

        /* We do not add the symbol to the dynamic symbol table if

           - the symbol is for a file
           - it is not externally visible (internal, hidden)
           - if export_all_dynamic is not set and is only defined in
             the executable (i.e., it is defined, but not (also) in
             in DSO)

           Set symstrent[cnt] to NULL in case an entry is ignored.  */
        if (XELF_ST_TYPE (sym->st_info) == STT_FILE
            || XELF_ST_VISIBILITY (sym->st_other) == STV_INTERNAL
            || XELF_ST_VISIBILITY (sym->st_other) == STV_HIDDEN
            || (!ld_state.export_all_dynamic
              && !ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined))
          {
            symstrent[cnt] = NULL;
            continue;
          }

        size_t idx;
        if (ndxtosym[cnt]->in_dso && ndxtosym[cnt]->type == STT_FUNC)
          {
            idx = plt_idx++;
            assert (idx < 1 + ld_state.nplt);
          }
        else
          {
            idx = obj_idx++;
            assert (idx < nsym_dyn_allocated);
          }

        /* Add the version information.  */
        if (versymdata != NULL)
          {
            struct symbol *symp = ndxtosym[cnt];

            /* Synthetic symbols (i.e., those with no file attached)
             have no version information.  */
            if (symp->file != NULL && symp->file->verdefdata != NULL)
            {
              GElf_Versym versym;

              gelf_getversym (symp->file->versymdata, symp->symidx,
                          &versym);

              (void) gelf_update_versym (versymdata, idx,
                                   &symp->file->verdefused[versym]);
            }
            else
            {
              /* XXX Add support for version definitions.  */
              GElf_Versym global = VER_NDX_GLOBAL;
              (void) gelf_update_versym (versymdata, idx, &global);
            }
          }

        /* Store the index of the symbol in the dynamic symbol table.  */
        ndxtosym[cnt]->outdynsymidx = idx;

        /* Create a new string table entry.  */
        const char *str = ndxtosym[cnt]->name;
        symstrent[cnt] = ebl_strtabadd (dynstrtab, str, 0);
        hashcodes[idx] = elf_hash (str);
        ++nsym_dyn;
      }
      assert (nsym_dyn == obj_idx);
      assert (ld_state.nplt + 1 == plt_idx);

      /* Update the information about the symbol section.  */
      if (versymdata != NULL)
      {
        /* Correct the size now that we know how many entries the
           dynamic symbol table has.  */
        versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF,
                                 nsym_dyn);

        /* Add the reference to the symbol table.  */
        xelf_getshdr (versymscn, shdr);
        assert (shdr != NULL);

        shdr->sh_link = ld_state.dynsymscnidx;

        (void) xelf_update_shdr (versymscn, shdr);
      }
    }

  if (ld_state.file_type != relocatable_file_type)
    {
      size_t nbucket;
      Elf32_Word *bucket;
      Elf32_Word *chain;
      size_t nchain;
      Elf_Scn *hashscn;
      Elf_Data *hashdata;

      /* Finalize the dynamic string table.  */
      ebl_strtabfinalize (dynstrtab, dynstrdata);

      /* Determine the "optimal" bucket size.  */
      nbucket = optimal_bucket_size (hashcodes, nsym_dyn, ld_state.optlevel);

      /* Create the .hash section data structures.  */
      assert (ld_state.hashscnidx != 0);
      hashscn = elf_getscn (ld_state.outelf, ld_state.hashscnidx);
      xelf_getshdr (hashscn, shdr);
      hashdata = elf_newdata (hashscn);
      if (shdr == NULL || hashdata == NULL)
      error (EXIT_FAILURE, 0, gettext ("\
cannot create hash table section for output file: %s"),
             elf_errmsg (-1));

      shdr->sh_link = ld_state.dynsymscnidx;
      (void) xelf_update_shdr (hashscn, shdr);

      hashdata->d_size = (2 + nsym_dyn + nbucket) * sizeof (Elf32_Word);
      hashdata->d_buf = xcalloc (1, hashdata->d_size);
      hashdata->d_align = sizeof (Elf32_Word);
      hashdata->d_type = ELF_T_WORD;
      hashdata->d_off = 0;

      ((Elf32_Word *) hashdata->d_buf)[0] = nbucket;
      ((Elf32_Word *) hashdata->d_buf)[1] = nsym_dyn;
      bucket = &((Elf32_Word *) hashdata->d_buf)[2];
      chain = &((Elf32_Word *) hashdata->d_buf)[2 + nbucket];

      /* Haven't yet filled in any chain value.  */
      nchain = 0;

      /* Now put the names in.  */
      for (cnt = nsym_local; cnt < nsym; ++cnt)
      if (symstrent[cnt] != NULL)
        {
          XElf_Sym_vardef (sym);
          size_t dynidx = ndxtosym[cnt]->outdynsymidx;

#if NATIVE_ELF != 0
          XElf_Sym *osym;
          memcpy (xelf_getsym (dynsymdata, dynidx, sym),
                xelf_getsym (symdata, cnt, osym),
                sizeof (XElf_Sym));
#else
          xelf_getsym (symdata, cnt, sym);
          assert (sym != NULL);
#endif

          sym->st_name = ebl_strtaboffset (symstrent[cnt]);

          (void) xelf_update_sym (dynsymdata, dynidx, sym);

          /* Add to the hash table.  */
          size_t hashidx = hashcodes[dynidx] % nbucket;
          if (bucket[hashidx] == 0)
            bucket[hashidx] = dynidx;
          else
            {
            hashidx = bucket[hashidx];
            while (chain[hashidx] != 0)
              hashidx = chain[hashidx];

            chain[hashidx] = dynidx;
            }
        }

      free (hashcodes);

      /* We don't need the map from the symbol table index to the symbol
       structure anymore.  */
      free (ndxtosym);

      /* Create the required version section.  */
      if (ld_state.verneedscnidx != 0)
      {
        Elf_Scn *verneedscn;
        Elf_Data *verneeddata;
        struct usedfiles *runp;
        size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1);
        size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1);
        size_t offset;
        int ntotal;

        verneedscn = elf_getscn (ld_state.outelf, ld_state.verneedscnidx);
        xelf_getshdr (verneedscn, shdr);
        verneeddata = elf_newdata (verneedscn);
        if (shdr == NULL || verneeddata == NULL)
          error (EXIT_FAILURE, 0,
               gettext ("cannot create versioning data: %s"),
               elf_errmsg (-1));

        verneeddata->d_size = (ld_state.nverdeffile * verneed_size
                         + ld_state.nverdefused * vernaux_size);
        verneeddata->d_buf = xmalloc (verneeddata->d_size);
        verneeddata->d_type = ELF_T_VNEED;
        verneeddata->d_align = xelf_fsize (ld_state.outelf, ELF_T_WORD, 1);
        verneeddata->d_off = 0;

        offset = 0;
        ntotal = ld_state.nverdeffile;
        runp = ld_state.dsofiles->next;
        do
          {
            offset = create_verneed_data (offset, verneeddata, runp,
                                  &ntotal);
            runp = runp->next;
          }
        while (ntotal > 0 && runp != ld_state.dsofiles->next);

        if (ntotal > 0)
          {
            runp = ld_state.needed->next;
            do
            {
              offset = create_verneed_data (offset, verneeddata, runp,
                                    &ntotal);
              runp = runp->next;
            }
            while (ntotal > 0 && runp != ld_state.needed->next);
          }

        assert (offset == verneeddata->d_size);

        /* Add the needed information to the section header.  */
        shdr->sh_link = ld_state.dynstrscnidx;
        shdr->sh_info = ld_state.nverdeffile;
        (void) xelf_update_shdr (verneedscn, shdr);
      }

      /* Adjust the section size.  */
      dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_dyn);
      if (versymdata != NULL)
      versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF,
                               nsym_dyn);

      /* Add the remaining information to the section header.  */
      xelf_getshdr (dynsymscn, shdr);
      /* There is always exactly one local symbol.  */
      shdr->sh_info = 1;
      /* Reference the string table.  */
      shdr->sh_link = ld_state.dynstrscnidx;
      /* Write the updated info back.  */
      (void) xelf_update_shdr (dynsymscn, shdr);
    }
  else
    /* We don't need the map from the symbol table index to the symbol
       structure anymore.  */
    free (ndxtosym);

  /* We don't need the string table anymore.  */
  free (symstrent);

  /* Remember the total number of symbols in the dynamic symbol table.  */
  ld_state.ndynsym = nsym_dyn;

  /* Fill in the section header information.  */
  symscn = elf_getscn (ld_state.outelf, ld_state.symscnidx);
  xelf_getshdr (symscn, shdr);
  if (shdr == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot create symbol table for output file: %s"),
         elf_errmsg (-1));

  shdr->sh_type = SHT_SYMTAB;
  shdr->sh_link = ld_state.strscnidx;
  shdr->sh_info = nsym_local;
  shdr->sh_entsize = xelf_fsize (ld_state.outelf, ELF_T_SYM, 1);

  (void) xelf_update_shdr (symscn, shdr);


  /* Add names for the generated sections.  */
  if (ld_state.symscnidx != 0)
      symtab_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab", 8);
  if (ld_state.xndxscnidx != 0)
    xndx_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab_shndx", 14);
  if (ld_state.strscnidx != 0)
    strtab_ent = ebl_strtabadd (ld_state.shstrtab, ".strtab", 8);
  /* At this point we would have to test for failures in the
     allocation.  But we skip this.  First, the problem will be caught
     later when doing more allocations for the section header table.
     Even if this would not be the case all that would happen is that
     the section names are empty.  The binary would still be usable if
     it is an executable or a DSO.  Not adding the test here saves
     quite a bit of code.  */


  /* Finally create the section for the section header string table.  */
  shstrtab_scn = elf_newscn (ld_state.outelf);
  shstrtab_ndx = elf_ndxscn (shstrtab_scn);
  if (unlikely (shstrtab_ndx == SHN_UNDEF))
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section header string section: %s"),
         elf_errmsg (-1));

  /* Add the name of the section to the string table.  */
  shstrtab_ent = ebl_strtabadd (ld_state.shstrtab, ".shstrtab", 10);
  if (unlikely (shstrtab_ent == NULL))
    error (EXIT_FAILURE, errno,
         gettext ("cannot create section header string section"));

  /* Finalize the section header string table.  */
  data = elf_newdata (shstrtab_scn);
  if (data == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section header string section: %s"),
         elf_errmsg (-1));
  ebl_strtabfinalize (ld_state.shstrtab, data);

  /* Now we know the string offsets for all section names.  */
  for (cnt = 0; cnt < ld_state.nallsections; ++cnt)
    if (ld_state.allsections[cnt]->scnidx != 0)
      {
      Elf_Scn *scn;

      scn = elf_getscn (ld_state.outelf, ld_state.allsections[cnt]->scnidx);

      xelf_getshdr (scn, shdr);
      assert (shdr != NULL);

      shdr->sh_name = ebl_strtaboffset (ld_state.allsections[cnt]->nameent);

      if (xelf_update_shdr (scn, shdr) == 0)
        assert (0);
      }

  /* Add the names for the generated sections to the respective
     section headers.  */
  if (symtab_ent != NULL)
    {
      Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.symscnidx);

      xelf_getshdr (scn, shdr);
      /* This cannot fail, we already accessed the header before.  */
      assert (shdr != NULL);

      shdr->sh_name = ebl_strtaboffset (symtab_ent);

      (void) xelf_update_shdr (scn, shdr);
    }
  if (xndx_ent != NULL)
    {
      Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.xndxscnidx);

      xelf_getshdr (scn, shdr);
      /* This cannot fail, we already accessed the header before.  */
      assert (shdr != NULL);

      shdr->sh_name = ebl_strtaboffset (xndx_ent);

      (void) xelf_update_shdr (scn, shdr);
    }
  if (strtab_ent != NULL)
    {
      Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.strscnidx);

      xelf_getshdr (scn, shdr);
      /* This cannot fail, we already accessed the header before.  */
      assert (shdr != NULL);

      shdr->sh_name = ebl_strtaboffset (strtab_ent);

      (void) xelf_update_shdr (scn, shdr);
    }

  /* And the section header table section itself.  */
  xelf_getshdr (shstrtab_scn, shdr);
  if (shdr == NULL)
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section header string section: %s"),
         elf_errmsg (-1));

  shdr->sh_name = ebl_strtaboffset (shstrtab_ent);
  shdr->sh_type = SHT_STRTAB;

  if (unlikely (xelf_update_shdr (shstrtab_scn, shdr) == 0))
    error (EXIT_FAILURE, 0,
         gettext ("cannot create section header string section: %s"),
         elf_errmsg (-1));


  /* Add the correct section header info to the section group sections.  */
  groups = ld_state.groups;
  while (groups != NULL)
    {
      Elf_Scn *scn = elf_getscn (ld_state.outelf, groups->outscnidx);
      xelf_getshdr (scn, shdr);
      assert (shdr != NULL);

      shdr->sh_name = ebl_strtaboffset (groups->nameent);
      shdr->sh_type = SHT_GROUP;
      shdr->sh_flags = 0;
      shdr->sh_link = ld_state.symscnidx;
      shdr->sh_entsize = sizeof (Elf32_Word);

      /* Determine the index for the signature symbol.  */
      Elf32_Word si
      = groups->symbol->file->symindirect[groups->symbol->symidx];
      if (si == 0)
      {
        assert (groups->symbol->file->symref[groups->symbol->symidx]
              != NULL);
        si = groups->symbol->file->symref[groups->symbol->symidx]->outsymidx;
        assert (si != 0);
      }
      shdr->sh_info = ld_state.dblindirect[si];

      (void) xelf_update_shdr (scn, shdr);

      struct scngroup *oldp = groups;
      groups = groups->next;
      free (oldp);
    }


  if (ld_state.file_type != relocatable_file_type)
    {
      size_t nphdr;
      XElf_Addr addr;
      struct output_segment *segment;
      Elf_Scn *scn;
      Elf32_Word nsec;
      XElf_Phdr_vardef (phdr);

      /* Every executable needs a program header.  The number of entries
       varies.  One exists for each segment.  Each SHT_NOTE section gets
       one, too.  For dynamically linked executables we have to create
       one for the program header, the interpreter, and the dynamic
       section.  First count the number of segments.

       XXX Determine whether the segment is non-empty.  */
      nphdr = 0;

      /* We always add a PT_GNU_stack entry.  */
      ++nphdr;

      segment = ld_state.output_segments;
      while (segment != NULL)
      {
        ++nphdr;
        segment = segment->next;
      }

      /* Add the number of SHT_NOTE sections.  We counted them earlier.  */
      nphdr += ld_state.nnotesections;

      /* If we create a DSO or the file is linked against DSOs we have
       at least one more entry: DYNAMIC.  If an interpreter is
       specified we add PHDR and INTERP, too.  */
      if (dynamically_linked_p ())
      {
        ++nphdr;

        if (ld_state.interp != NULL || ld_state.file_type != dso_file_type)
          nphdr += 2;
      }

      /* Create the program header structure.  */
      if (xelf_newphdr (ld_state.outelf, nphdr) == 0)
      error (EXIT_FAILURE, 0, gettext ("cannot create program header: %s"),
             elf_errmsg (-1));


      /* Determine the section sizes and offsets.  We have to do this
       to be able to determine the memory layout (which normally
       differs from the file layout).  */
      if (elf_update (ld_state.outelf, ELF_C_NULL) == -1)
      error (EXIT_FAILURE, 0, gettext ("while determining file layout: %s"),
             elf_errmsg (-1));


      /* Now determine the memory addresses of all the sections and
       segments.  */
      nsec = 0;
      scn = elf_getscn (ld_state.outelf, ld_state.allsections[nsec]->scnidx);
      xelf_getshdr (scn, shdr);
      assert (shdr != NULL);

      /* The address we start with is the offset of the first (not
       zeroth) section.  */
      addr = shdr->sh_offset;

      /* The index of the first loadable segment.  */
      nphdr = 0;
      if (dynamically_linked_p ())
      {
        ++nphdr;
        if (ld_state.interp != NULL
            || ld_state.file_type != dso_file_type)
          nphdr += 2;
      }

      segment = ld_state.output_segments;
      while (segment != NULL)
      {
        struct output_rule *orule;
        bool first_section = true;
        XElf_Off nobits_size = 0;
        XElf_Off memsize = 0;

        /* the minimum alignment is a page size.  */
        segment->align = ld_state.pagesize;

        for (orule = segment->output_rules; orule != NULL;
             orule = orule->next)
          if (orule->tag == output_section)
            {
            XElf_Off oldoff;

            /* See whether this output rule corresponds to the next
               section.  Yes, this is a pointer comparison.  */
            if (ld_state.allsections[nsec]->name
                != orule->val.section.name)
              /* No, ignore this output rule.  */
              continue;

            /* We assign addresses only in segments which are actually
               loaded.  */
            if (segment->mode != 0)
              {
                /* Adjust the offset of the input sections.  */
                struct scninfo *isect;
                struct scninfo *first;

                isect = first = ld_state.allsections[nsec]->last;
                if (isect != NULL)
                  do
                  isect->offset += addr;
                  while ((isect = isect->next) != first);

                /* Set the address of current section.  */
                shdr->sh_addr = addr;

                /* Write the result back.  */
                (void) xelf_update_shdr (scn, shdr);

                /* Remember the address.  */
                ld_state.allsections[nsec]->addr = addr;
              }

            if (first_section)
              {
                /* The first segment starts at offset zero.  */
                if (segment == ld_state.output_segments)
                  {
                  segment->offset = 0;
                  segment->addr = addr - shdr->sh_offset;
                  }
                else
                  {
                  segment->offset = shdr->sh_offset;
                  segment->addr = addr;
                  }

                /* Determine the maximum alignment requirement.  */
                segment->align = MAX (segment->align, shdr->sh_addralign);

                first_section = false;
              }

            memsize = shdr->sh_offset - segment->offset + shdr->sh_size;
            if (nobits_size != 0 && shdr->sh_type != SHT_NOTE)
              error (EXIT_FAILURE, 0, gettext ("\
internal error: nobits section follows nobits section"));
            if (shdr->sh_type == SHT_NOBITS)
              nobits_size += shdr->sh_size;

            /* Determine the new address which is computed using
               the difference of the offsets on the sections.  Note
               that this assumes that the sections following each
               other in the section header table are also
               consecutive in the file.  This is true here because
               libelf constructs files this way.  */
            oldoff = shdr->sh_offset;

            if (++nsec >= ld_state.nallsections)
              break;

            scn = elf_getscn (ld_state.outelf,
                          ld_state.allsections[nsec]->scnidx);
            xelf_getshdr (scn, shdr);
            assert (shdr != NULL);

            /* This is the new address resulting from the offsets
               in the file.  */
            assert (oldoff <= shdr->sh_offset);
            addr += shdr->sh_offset - oldoff;
            }
          else
            {
            assert (orule->tag == output_assignment);

            if (strcmp (orule->val.assignment->variable, ".") == 0)
              /* This is a change of the address.  */
              addr = eval_expression (orule->val.assignment->expression,
                                addr);
            else if (orule->val.assignment->sym != NULL)
              {
                /* This symbol is used.  Update the symbol table
                   entry.  */
                XElf_Sym_vardef (sym);
                size_t idx;

                /* Note that we do not have to use
                   xelf_getsymshndx since we only update the
                   symbol address, not the section
                   information.  */
                idx = dblindirect[orule->val.assignment->sym->outsymidx];
                xelf_getsym (symdata, idx, sym);
                sym->st_value = addr;
                (void) xelf_update_sym (symdata, idx, sym);

                idx = orule->val.assignment->sym->outdynsymidx;
                if (idx != 0)
                  {
                  assert (dynsymdata != NULL);
                  xelf_getsym (dynsymdata, idx, sym);
                  sym->st_value = addr;
                  (void) xelf_update_sym (dynsymdata, idx, sym);
                  }
              }
            }

        /* Store the segment parameter for loadable segments.  */
        if (segment->mode != 0)
          {
            xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr);

            phdr->p_type = PT_LOAD;
            phdr->p_offset = segment->offset;
            phdr->p_vaddr = segment->addr;
            phdr->p_paddr = phdr->p_vaddr;
            phdr->p_filesz = memsize - nobits_size;
            phdr->p_memsz = memsize;
            phdr->p_flags = segment->mode;
            phdr->p_align = segment->align;

            (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr);
            ++nphdr;
          }

        segment = segment->next;
      }

      /* Create the other program header entries.  */
      xelf_getehdr (ld_state.outelf, ehdr);
      assert (ehdr != NULL);

      /* Add the stack information.  */
      xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr);
      phdr->p_type = PT_GNU_STACK;
      phdr->p_offset = 0;
      phdr->p_vaddr = 0;
      phdr->p_paddr = 0;
      phdr->p_filesz = 0;
      phdr->p_memsz = 0;
      phdr->p_flags = ld_state.execstack == execstack_true ? PF_X : 0;
      phdr->p_align = 0;

      (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr);
      ++nphdr;


      /* Adjust the addresses in the address fields of the symbol
       records according to the load addresses of the sections.  */
      if (ld_state.need_symtab)
      for (cnt = 1; cnt < nsym; ++cnt)
        {
          XElf_Sym_vardef (sym);
          Elf32_Word shndx;

          xelf_getsymshndx (symdata, xndxdata, cnt, sym, shndx);
          assert (sym != NULL);

          if (sym->st_shndx != SHN_XINDEX)
            shndx = sym->st_shndx;

          if ((shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
            || shndx > SHN_HIRESERVE)
            {
            /* Note we subtract 1 from the section index since ALLSECTIONS
               does not store the dummy section with offset zero.  */
            sym->st_value += ld_state.allsections[shndx - 1]->addr;

            /* We don't have to use 'xelf_update_symshndx' since the
               section number doesn't change.  */
            (void) xelf_update_sym (symdata, cnt, sym);
            }
        }

      if (ld_state.need_dynsym)
      for (cnt = 1; cnt < nsym_dyn; ++cnt)
        {
          XElf_Sym_vardef (sym);

          xelf_getsym (dynsymdata, cnt, sym);
          assert (sym != NULL);

          if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
            {
            /* Note we subtract 1 from the section index since ALLSECTIONS
               does not store the dummy section with offset zero.  */
            sym->st_value += ld_state.allsections[sym->st_shndx - 1]->addr;

            /* We don't have to use 'xelf_update_symshndx' since the
               section number doesn't change.  */
            (void) xelf_update_sym (dynsymdata, cnt, sym);
            }
        }


      /* Now is a good time to determine the values of all the symbols
       we encountered.  */
      // XXX This loop is very inefficient.  The hash tab iterator also
      // returns all symbols in DSOs.
      struct symbol *se;
      void *p = NULL;
      while ((se = ld_symbol_tab_iterate (&ld_state.symbol_tab, &p)) != NULL)
      if (! se->in_dso)
        {
          XElf_Sym_vardef (sym);

          addr = 0;

          if (se->outdynsymidx != 0)
            {
            xelf_getsym (dynsymdata, se->outdynsymidx, sym);
            assert (sym != NULL);
            addr = sym->st_value;
            }
          else if (se->outsymidx != 0)
            {
            assert (dblindirect[se->outsymidx] != 0);
            xelf_getsym (symdata, dblindirect[se->outsymidx], sym);
            assert (sym != NULL);
            addr = sym->st_value;
            }
          else
            abort ();

          se->merge.value = addr;
        }

      /* Complete the header of the .rel.dyn/.rela.dyn section.  Point
       to the symbol table.  The sh_info field is left zero since
       there is no specific section the contained relocations are
       for.  */
      if (ld_state.reldynscnidx != 0)
      {
        assert (ld_state.dynsymscnidx != 0);
        scn = elf_getscn (ld_state.outelf, ld_state.reldynscnidx);
        xelf_getshdr (scn, shdr);
        assert (shdr != NULL);

        shdr->sh_link = ld_state.dynsymscnidx;

        (void) xelf_update_shdr (scn, shdr);
      }

      /* Fill in the dynamic segment/section.  */
      if (dynamically_linked_p ())
      {
        Elf_Scn *outscn;

        int idx = 0;
        if (ld_state.interp != NULL || ld_state.file_type != dso_file_type)
          {
            assert (ld_state.interpscnidx != 0);
            xelf_getshdr (elf_getscn (ld_state.outelf,
                              ld_state.interpscnidx), shdr);
            assert (shdr != NULL);

            xelf_getphdr_ptr (ld_state.outelf, idx, phdr);
            phdr->p_type = PT_PHDR;
            phdr->p_offset = ehdr->e_phoff;
            phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset;
            phdr->p_paddr = phdr->p_vaddr;
            phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize;
            phdr->p_memsz = phdr->p_filesz;
            phdr->p_flags = 0;      /* No need to set PF_R or so.  */
            phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1);

            (void) xelf_update_phdr (ld_state.outelf, idx, phdr);
            ++idx;

            /* The interpreter string.  */
            xelf_getphdr_ptr (ld_state.outelf, idx, phdr);
            phdr->p_type = PT_INTERP;
            phdr->p_offset = shdr->sh_offset;
            phdr->p_vaddr = shdr->sh_addr;
            phdr->p_paddr = phdr->p_vaddr;
            phdr->p_filesz = shdr->sh_size;
            phdr->p_memsz = phdr->p_filesz;
            phdr->p_flags = 0;      /* No need to set PF_R or so.  */
            phdr->p_align = 1;      /* It's a string.  */

            (void) xelf_update_phdr (ld_state.outelf, idx, phdr);
            ++idx;
          }

        /* The pointer to the dynamic section.  We this we need to
           get the information for the dynamic section first.  */
        assert (ld_state.dynamicscnidx);
        outscn = elf_getscn (ld_state.outelf, ld_state.dynamicscnidx);
        xelf_getshdr (outscn, shdr);
        assert (shdr != NULL);

        xelf_getphdr_ptr (ld_state.outelf, idx, phdr);
        phdr->p_type = PT_DYNAMIC;
        phdr->p_offset = shdr->sh_offset;
        phdr->p_vaddr = shdr->sh_addr;
        phdr->p_paddr = phdr->p_vaddr;
        phdr->p_filesz = shdr->sh_size;
        phdr->p_memsz = phdr->p_filesz;
        phdr->p_flags = 0;          /* No need to set PF_R or so.  */
        phdr->p_align = shdr->sh_addralign;

        (void) xelf_update_phdr (ld_state.outelf, idx, phdr);

        /* Fill in the reference to the .dynstr section.  */
        assert (ld_state.dynstrscnidx != 0);
        shdr->sh_link = ld_state.dynstrscnidx;
        (void) xelf_update_shdr (outscn, shdr);

        /* And fill the remaining entries.  */
        Elf_Data *dyndata = elf_getdata (outscn, NULL);
        assert (dyndata != NULL);

        /* Add the DT_NEEDED entries.  */
        if (ld_state.ndsofiles > 0)
          {
            struct usedfiles *runp = ld_state.dsofiles->next;

            do
            if (runp->used || !runp->as_needed)
              {
                /* Add the position-dependent flag if necessary.  */
                if (runp->lazyload)
                  new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                               DT_POSFLAG_1, DF_P1_LAZYLOAD);

                new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                               DT_NEEDED,
                               ebl_strtaboffset (runp->sonameent));
              }
            while ((runp = runp->next) != ld_state.dsofiles->next);
          }

        /* We can finish the DT_RUNPATH/DT_RPATH entries now.  */
        if (ld_state.rxxpath_strent != NULL)
          new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         ld_state.rxxpath_tag,
                         ebl_strtaboffset (ld_state.rxxpath_strent));

        /* Reference to initialization and finalization functions.  */
        // XXX This code depends on symbol table being relocated.
        if (ld_state.init_symbol != NULL)
          {
            XElf_Sym_vardef (sym);

            if (ld_state.need_symtab)
            xelf_getsym (symdata,
                       dblindirect[ld_state.init_symbol->outsymidx],
                       sym);
            else
            xelf_getsym (dynsymdata, ld_state.init_symbol->outdynsymidx,
                       sym);
            assert (sym != NULL);

            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_INIT, sym->st_value);
          }
        if (ld_state.fini_symbol != NULL)
          {
            XElf_Sym_vardef (sym);

            if (ld_state.need_symtab)
            xelf_getsym (symdata,
                       dblindirect[ld_state.fini_symbol->outsymidx],
                       sym);
            else
            xelf_getsym (dynsymdata, ld_state.fini_symbol->outdynsymidx,
                       sym);
            assert (sym != NULL);

            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_FINI, sym->st_value);
          }
        // XXX Support init,fini,preinit arrays

        /* The hash table which comes with dynamic symbol table.  */
        xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.hashscnidx),
                  shdr);
        assert (shdr != NULL);
        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_HASH,
                       shdr->sh_addr);

        /* Reference to the symbol table section.  */
        assert (ld_state.dynsymscnidx != 0);
        xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynsymscnidx),
                  shdr);
        assert (shdr != NULL);
        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMTAB,
                       shdr->sh_addr);

        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMENT,
                       xelf_fsize (ld_state.outelf, ELF_T_SYM, 1));

        /* And the string table which comes with it.  */
        xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynstrscnidx),
                  shdr);
        assert (shdr != NULL);
        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRTAB,
                       shdr->sh_addr);

        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRSZ,
                       shdr->sh_size);

        /* Add the entries related to the .plt.  */
        if (ld_state.nplt > 0)
          {
            xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.gotscnidx),
                      shdr);
            assert (shdr != NULL);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         // XXX This should probably be machine
                         // dependent.
                         DT_PLTGOT, shdr->sh_addr);

            xelf_getshdr (elf_getscn (ld_state.outelf,
                              ld_state.pltrelscnidx), shdr);
            assert (shdr != NULL);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_PLTRELSZ, shdr->sh_size);

            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_JMPREL, shdr->sh_addr);

            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_PLTREL, REL_TYPE (statep));
          }

        if (ld_state.relsize_total > 0)
          {
            int rel = REL_TYPE (statep);
            xelf_getshdr (elf_getscn (ld_state.outelf,
                              ld_state.reldynscnidx), shdr);
            assert (shdr != NULL);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         rel, shdr->sh_addr);

            /* Trick ahead.  Use arithmetic to get the right tag.
             We check the validity of this assumption in the asserts.  */
            assert (DT_RELASZ - DT_RELA == 1);
            assert (DT_RELSZ - DT_REL == 1);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         rel + 1, shdr->sh_size);

            /* Similar for the entry size tag.  */
            assert (DT_RELAENT - DT_RELA == 2);
            assert (DT_RELENT - DT_REL == 2);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         rel + 2,
                         rel == DT_REL
                         ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1)
                         : xelf_fsize (ld_state.outelf, ELF_T_RELA,
                                     1));
          }

        if (ld_state.verneedscnidx != 0)
          {
            xelf_getshdr (elf_getscn (ld_state.outelf,
                              ld_state.verneedscnidx), shdr);
            assert (shdr != NULL);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_VERNEED, shdr->sh_addr);

            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_VERNEEDNUM, ld_state.nverdeffile);
          }

        if (ld_state.versymscnidx != 0)
          {
            xelf_getshdr (elf_getscn (ld_state.outelf,
                              ld_state.versymscnidx), shdr);
            assert (shdr != NULL);
            new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_VERSYM, shdr->sh_addr);
          }

        /* We always create the DT_DEBUG entry.  */
        new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_DEBUG, 0);
        assert (ld_state.ndynamic_filled < ld_state.ndynamic);

        /* Add the flag words if necessary.  */
        if (ld_state.dt_flags != 0)
          new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_FLAGS,
                         ld_state.dt_flags);

        /* Create entry for the DT_FLAGS_1 flag.  */
        if (ld_state.dt_flags_1 != 0)
          new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_FLAGS_1, ld_state.dt_flags_1);

        /* Create entry for the DT_FEATURE_1 flag.  */
        if (ld_state.dt_feature_1 != 0)
          new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                         DT_FEATURE_1, ld_state.dt_feature_1);

        assert (ld_state.ndynamic_filled <= ld_state.ndynamic);
      }
    }


  // XXX The following code isn't nice.  We use two different
  // mechanisms to handle relocations, one for relocatable files, one
  // for executables and DSOs.  Maybe this is the best method but also
  // maybe it can be somewhat unified.

  /* Now that we created the symbol table we can add the reference to
     it in the sh_link field of the section headers of the relocation
     sections.  */
  while (rellist != NULL)
    {
      assert (ld_state.file_type == relocatable_file_type);
      Elf_Scn *outscn;

      outscn = elf_getscn (ld_state.outelf, rellist->scnidx);
      xelf_getshdr (outscn, shdr);
      /* This must not fail since we did it before.  */
      assert (shdr != NULL);

      /* Remember the symbol table which belongs to the relocation section.  */
      shdr->sh_link = ld_state.symscnidx;

      /* And the reference to the section which is relocated by this
       relocation section.  We use the info from the first input
       section but all records should have the same information.  */
      shdr->sh_info =
      rellist->scninfo->fileinfo->scninfo[SCNINFO_SHDR (rellist->scninfo->shdr).sh_info].outscnndx;


      /* Perform the actual relocations.  We only have to adjust
       offsets and symbol indices.  */
      RELOCATE_SECTION (statep, outscn, rellist->scninfo, dblindirect);

      /* Store the changes.  */
      (void) xelf_update_shdr (outscn, shdr);

      /* Up to the next relocation section.  */
      rellist = rellist->next;
    }

  if (ld_state.rellist != NULL)
    {
      assert (ld_state.file_type != relocatable_file_type);
      /* Create the relocations for the output file.  */
      CREATE_RELOCATIONS (statep, dblindirect);
    }


  /* We need the ELF header once more.  */
  xelf_getehdr (ld_state.outelf, ehdr);
  assert (ehdr != NULL);

  /* Set the section header string table index.  */
  if (likely (shstrtab_ndx < SHN_HIRESERVE)
      && likely (shstrtab_ndx != SHN_XINDEX))
    ehdr->e_shstrndx = shstrtab_ndx;
  else
    {
      /* We have to put the section index in the sh_link field of the
       zeroth section header.  */
      Elf_Scn *scn = elf_getscn (ld_state.outelf, 0);

      xelf_getshdr (scn, shdr);
      if (unlikely (shdr == NULL))
      error (EXIT_FAILURE, 0,
             gettext ("cannot get header of 0th section: %s"),
             elf_errmsg (-1));

      shdr->sh_link = shstrtab_ndx;

      (void) xelf_update_shdr (scn, shdr);

      ehdr->e_shstrndx = SHN_XINDEX;
    }

  if (ld_state.file_type != relocatable_file_type)
    /* DSOs and executables have to define the entry point symbol.  */
    ehdr->e_entry = find_entry_point ();

  if (unlikely (xelf_update_ehdr (ld_state.outelf, ehdr) == 0))
    error (EXIT_FAILURE, 0,
         gettext ("cannot update ELF header: %s"),
         elf_errmsg (-1));


  /* Free the data which we don't need anymore.  */
  free (ld_state.dblindirect);


  /* Finalize the .plt section the what belongs to them.  */
  FINALIZE_PLT (statep, nsym, nsym_dyn);

  return 0;
}


/* This is a function which must be specified in all backends.  */
static void
ld_generic_relocate_section (struct ld_state *statep, Elf_Scn *outscn,
                       struct scninfo *firstp,
                       const Elf32_Word *dblindirect)
{
  error (EXIT_FAILURE, 0, gettext ("\
linker backend didn't specify function to relocate section"));
  /* NOTREACHED */
}


/* Finalize the output file.  */
static int
ld_generic_finalize (struct ld_state *statep)
{
  /* Write out the ELF file data.  */
  if (elf_update (ld_state.outelf, ELF_C_WRITE) == -1)
      error (EXIT_FAILURE, 0, gettext ("while writing output file: %s"),
           elf_errmsg (-1));

  /* Free the resources.  */
  if (elf_end (ld_state.outelf) != 0)
    error (EXIT_FAILURE, 0, gettext ("while finishing output file: %s"),
         elf_errmsg (-1));

  /* Get the file status of the temporary file.  */
  struct stat temp_st;
  if (fstat (ld_state.outfd, &temp_st) != 0)
    error (EXIT_FAILURE, errno, gettext ("cannot stat output file"));

  /* Now it's time to rename the file.  Remove an old existing file
     first.  */
  if (rename (ld_state.tempfname, ld_state.outfname) != 0)
    /* Something went wrong.  */
    error (EXIT_FAILURE, errno, gettext ("cannot rename output file"));

  /* Make sure the output file is really the one we created.  */
  struct stat new_st;
  if (stat (ld_state.outfname, &new_st) != 0
      || new_st.st_ino != temp_st.st_ino
      || new_st.st_dev != temp_st.st_dev)
    {
      /* Wow, somebody overwrote the output file, probably some intruder.  */
      unlink (ld_state.outfname);
      error (EXIT_FAILURE, 0, gettext ("\
WARNING: temporary output file overwritten before linking finished"));
    }

  /* Close the file descriptor.  */
  (void) close (ld_state.outfd);

  /* Signal the cleanup handler that the file is correctly created.  */
  ld_state.tempfname = NULL;

  return 0;
}


static bool
ld_generic_special_section_number_p (struct ld_state *statep, size_t number)
{
  /* There are no special section numbers in the gABI.  */
  return false;
}


static bool
ld_generic_section_type_p (struct ld_state *statep, GElf_Word type)
{
  if (type < SHT_NUM
      /* XXX Enable the following two when implemented.  */
      // || type == SHT_GNU_LIBLIST
      // || type == SHT_CHECKSUM
      /* XXX Eventually include SHT_SUNW_move, SHT_SUNW_COMDAT, and
       SHT_SUNW_syminfo.  */
      || (type >= SHT_GNU_verdef && type <= SHT_GNU_versym))
    return true;

  return false;
}


static XElf_Xword
ld_generic_dynamic_section_flags (struct ld_state *statep)
{
  /* By default the .dynamic section is writable (and is of course
     loaded).  Few architecture differ from this.  */
  return SHF_ALLOC | SHF_WRITE;
}


static void
ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "initialize_plt");
}


static void
ld_generic_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "initialize_pltrel");
}


static void
ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "initialize_got");
}


static void
ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, size_t nsym_dyn)
{
  /* By default we assume that nothing has to be done.  */
}


static int
ld_generic_rel_type (struct ld_state *statep)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "rel_type");
  /* Just to keep the compiler calm.  */
  return 0;
}


static void
ld_generic_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "count_relocations");
}


static void
ld_generic_create_relocations (struct ld_state *statep,
                         const Elf32_Word *dblindirect)
{
  /* This cannot be implemented generally.  There should have been a
     machine dependent implementation and we should never have arrived
     here.  */
  error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"),
       "create_relocations");
}

Generated by  Doxygen 1.6.0   Back to index