Change PLT code to avoid using r2 - it used by GCC to return large startures
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 749d13981c96e0e3f978064dbee5ad0f8c253537..0f5c71252035be930b51c2f8d0d20414ec2c080f 100644 (file)
@@ -1,5 +1,6 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -35,7 +36,7 @@ static boolean elf_link_add_archive_symbols
 static boolean elf_merge_symbol
   PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
           asection **, bfd_vma *, struct elf_link_hash_entry **,
-          boolean *, boolean *, boolean *));
+          boolean *, boolean *, boolean *, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_fix_symbol_flags
@@ -50,14 +51,14 @@ static boolean elf_link_assign_sym_version
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_collect_hash_codes
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_read_relocs_from_section 
+static boolean elf_link_read_relocs_from_section
   PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
 static void elf_link_output_relocs
   PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
 static boolean elf_link_size_reloc_section
   PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
-static void elf_link_adjust_relocs 
-  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, 
+static void elf_link_adjust_relocs
+  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
           struct elf_link_hash_entry **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
@@ -80,9 +81,9 @@ elf_bfd_link_add_symbols (abfd, info)
     }
 }
 \f
-/* Return true iff this is a non-common definition of a symbol.  */
+/* Return true iff this is a non-common, definition of a non-function symbol.  */
 static boolean
-is_global_symbol_definition (abfd, sym)
+is_global_data_symbol_definition (abfd, sym)
      bfd * abfd ATTRIBUTE_UNUSED;
      Elf_Internal_Sym * sym;
 {
@@ -91,10 +92,14 @@ is_global_symbol_definition (abfd, sym)
       && ELF_ST_BIND (sym->st_info) < STB_LOOS)
     return false;
 
+  /* Function symbols do not count.  */
+  if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+    return false;
+
   /* If the section is undefined, then so is the symbol.  */
   if (sym->st_shndx == SHN_UNDEF)
     return false;
-  
+
   /* If the symbol is defined in the common section, then
      it is a common definition and so does not count.  */
   if (sym->st_shndx == SHN_COMMON)
@@ -104,20 +109,19 @@ is_global_symbol_definition (abfd, sym)
      must rely upon the backend to tell us what it is.  */
   if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
     /* FIXME - this function is not coded yet:
-       
+
        return _bfd_is_global_symbol_definition (abfd, sym);
-       
+
        Instead for now assume that the definition is not global,
        Even if this is wrong, at least the linker will behave
        in the same way that it used to do.  */
     return false;
-      
+
   return true;
 }
 
-
 /* Search the symbol table of the archive element of the archive ABFD
-   whoes archove map contains a mention of SYMDEF, and determine if
+   whoes archive map contains a mention of SYMDEF, and determine if
    the symbol is defined in this element.  */
 static boolean
 elf_link_is_defined_archive_symbol (abfd, symdef)
@@ -132,7 +136,7 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
   size_t extsymcount;
   size_t extsymoff;
   boolean result = false;
-  
+
   abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
   if (abfd == (bfd *) NULL)
     return false;
@@ -146,7 +150,7 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
      (re)include this element.  */
   if (abfd->archive_pass)
     return false;
-  
+
   /* Select the appropriate symbol table.  */
   if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
     hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -202,17 +206,16 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
 
       if (strcmp (name, symdef->name) == 0)
        {
-         result = is_global_symbol_definition (abfd, & sym);
+         result = is_global_data_symbol_definition (abfd, & sym);
          break;
        }
     }
 
   free (buf);
-  
+
   return result;
 }
 \f
-
 /* Add symbols from an ELF archive file to the linker hash table.  We
    don't use _bfd_generic_link_add_archive_symbols because of a
    problem which arises on UnixWare.  The UnixWare libc.so is an
@@ -433,11 +436,12 @@ elf_link_add_archive_symbols (abfd, info)
    TYPE_CHANGE_OK if it is OK for the type to change.  We set
    SIZE_CHANGE_OK if it is OK for the size to change.  By OK to
    change, we mean that we shouldn't warn if the type or size does
-   change.  */
+   change. DT_NEEDED indicates if it comes from a DT_NEEDED entry of
+   a shared object.  */
 
 static boolean
 elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
-                 override, type_change_ok, size_change_ok)
+                 override, type_change_ok, size_change_ok, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      const char *name;
@@ -448,6 +452,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      boolean *override;
      boolean *type_change_ok;
      boolean *size_change_ok;
+     boolean dt_needed;
 {
   asection *sec;
   struct elf_link_hash_entry *h;
@@ -624,9 +629,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
     olddyncommon = false;
 
   /* It's OK to change the type if either the existing symbol or the
-     new symbol is weak.  */
+     new symbol is weak unless it comes from a DT_NEEDED entry of
+     a shared object, in which case, the DT_NEEDED entry may not be
+     required at the run time.  */
 
-  if (h->root.type == bfd_link_hash_defweak
+  if ((! dt_needed && h->root.type == bfd_link_hash_defweak)
       || h->root.type == bfd_link_hash_undefweak
       || bind == STB_WEAK)
     *type_change_ok = true;
@@ -678,7 +685,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      object to override a weak symbol in a shared object.
 
      We prefer a non-weak definition in a shared library to a weak
-     definition in the executable.  */
+     definition in the executable unless it comes from a DT_NEEDED
+     entry of a shared object, in which case, the DT_NEEDED entry
+     may not be required at the run time.  */
 
   if (newdyn
       && newdef
@@ -687,6 +696,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
              && (bind == STB_WEAK
                  || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
       && (h->root.type != bfd_link_hash_defweak
+         || dt_needed
          || bind == STB_WEAK))
     {
       *override = true;
@@ -821,8 +831,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
   /* Handle the special case of a weak definition in a regular object
      followed by a non-weak definition in a shared object.  In this
-     case, we prefer the definition in the shared object.  */
+     case, we prefer the definition in the shared object unless it
+     comes from a DT_NEEDED entry of a shared object, in which case,
+     the DT_NEEDED entry may not be required at the run time.  */
   if (olddef
+      && ! dt_needed
       && h->root.type == bfd_link_hash_defweak
       && newdef
       && newdyn
@@ -882,7 +895,6 @@ elf_link_add_object_symbols (abfd, info)
   Elf_External_Sym *buf = NULL;
   struct elf_link_hash_entry **sym_hash;
   boolean dynamic;
-  bfd_byte *dynver = NULL;
   Elf_External_Versym *extversym = NULL;
   Elf_External_Versym *ever;
   Elf_External_Dyn *dynbuf = NULL;
@@ -890,7 +902,7 @@ elf_link_add_object_symbols (abfd, info)
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
   struct elf_backend_data *bed;
-  boolean visibility_changed = false;
+  boolean dt_needed;
 
   bed = get_elf_backend_data (abfd);
   add_symbol_hook = bed->elf_add_symbol_hook;
@@ -1010,7 +1022,7 @@ elf_link_add_object_symbols (abfd, info)
          Elf_Internal_Shdr *versymhdr;
 
          versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         extversym = (Elf_External_Versym *) bfd_malloc (hdr->sh_size);
+         extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
          if (extversym == NULL)
            goto error_return;
          if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
@@ -1050,6 +1062,8 @@ elf_link_add_object_symbols (abfd, info)
     goto error_return;
   elf_sym_hashes (abfd) = sym_hash;
 
+  dt_needed = false;
+
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -1086,7 +1100,12 @@ elf_link_add_object_symbols (abfd, info)
        {
          name = elf_dt_name (abfd);
          if (*name == '\0')
-           add_needed = false;
+           {
+             if (elf_dt_soname (abfd) != NULL)
+               dt_needed = true;
+
+             add_needed = false;
+           }
        }
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
@@ -1095,6 +1114,8 @@ elf_link_add_object_symbols (abfd, info)
          Elf_External_Dyn *extdynend;
          int elfsec;
          unsigned long link;
+         int rpath;
+         int runpath;
 
          dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size);
          if (dynbuf == NULL)
@@ -1128,6 +1149,8 @@ elf_link_add_object_symbols (abfd, info)
 
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+         rpath = 0;
+         runpath = 0;
          for (; extdyn < extdynend; extdyn++)
            {
              Elf_Internal_Dyn dyn;
@@ -1164,6 +1187,65 @@ elf_link_add_object_symbols (abfd, info)
                    ;
                  *pn = n;
                }
+             if (dyn.d_tag == DT_RUNPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+
+                 /* When we see DT_RPATH before DT_RUNPATH, we have
+                    to clear runpath.  Do _NOT_ bfd_release, as that
+                    frees all more recently bfd_alloc'd blocks as
+                    well.  */
+                 if (rpath && elf_hash_table (info)->runpath)
+                   elf_hash_table (info)->runpath = NULL;
+
+                 n = ((struct bfd_link_needed_list *)
+                      bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+                 fnm = bfd_elf_string_from_elf_section (abfd, link,
+                                                        dyn.d_un.d_val);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = &elf_hash_table (info)->runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+                 runpath = 1;
+                 rpath = 0;
+               }
+             /* Ignore DT_RPATH if we have seen DT_RUNPATH.  */
+             if (!runpath && dyn.d_tag == DT_RPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+
+                 n = ((struct bfd_link_needed_list *)
+                      bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+                 fnm = bfd_elf_string_from_elf_section (abfd, link,
+                                                        dyn.d_un.d_val);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = &elf_hash_table (info)->runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+                 rpath = 1;
+               }
            }
 
          free (dynbuf);
@@ -1239,7 +1321,7 @@ elf_link_add_object_symbols (abfd, info)
       /* Save the SONAME, if there is one, because sometimes the
          linker emulation code will need to know it.  */
       if (*name == '\0')
-       name = bfd_get_filename (abfd);
+       name = basename (bfd_get_filename (abfd));
       elf_dt_name (abfd) = name;
     }
 
@@ -1291,8 +1373,6 @@ elf_link_add_object_symbols (abfd, info)
          if (sym.st_shndx != SHN_UNDEF
              && sym.st_shndx != SHN_COMMON)
            flags = BSF_GLOBAL;
-         else
-           flags = 0;
        }
       else if (bind == STB_WEAK)
        flags = BSF_WEAK;
@@ -1458,7 +1538,7 @@ elf_link_add_object_symbols (abfd, info)
 
          if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
                                  sym_hash, &override, &type_change_ok,
-                                 &size_change_ok))
+                                 &size_change_ok, dt_needed))
            goto error_return;
 
          if (override)
@@ -1527,7 +1607,10 @@ elf_link_add_object_symbols (abfd, info)
          unsigned int align;
 
          align = bfd_log2 (sym.st_value);
-         if (align > old_alignment)
+         if (align > old_alignment
+             /* Permit an alignment power of zero if an alignment of one
+                is specified and no other alignments have been specified.  */
+             || (sym.st_value == 1 && old_alignment == 0))
            h->root.u.c.p->alignment_power = align;
        }
 
@@ -1579,13 +1662,10 @@ elf_link_add_object_symbols (abfd, info)
              /* Combine visibilities, using the most constraining one.  */
              unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
              unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
-             
+
              if (symvis && (hvis > symvis || hvis == 0))
-               {
-                 visibility_changed = true;
-                 h->other = sym.st_other;
-               }
-             
+               h->other = sym.st_other;
+
              /* If neither has visibility, use the st_other of the
                 definition.  This is an arbitrary choice, since the
                 other bits have no general meaning.  */
@@ -1637,7 +1717,7 @@ elf_link_add_object_symbols (abfd, info)
              name to the fully decorated name.  This will cause
              external references which do not specify a version to be
              bound to this version of the symbol.  */
-         if (definition)
+         if (definition || h->root.type == bfd_link_hash_common)
            {
              char *p;
 
@@ -1664,7 +1744,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (! override)
@@ -1781,7 +1862,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (override)
@@ -1855,18 +1937,65 @@ elf_link_add_object_symbols (abfd, info)
                    goto error_return;
                }
            }
-         else if (dynsym && h->dynindx != -1 && visibility_changed)
+         else if (dynsym && h->dynindx != -1)
            /* If the symbol already has a dynamic index, but
               visibility says it should not be visible, turn it into
               a local symbol.  */
            switch (ELF_ST_VISIBILITY (h->other))
              {
              case STV_INTERNAL:
-             case STV_HIDDEN:  
+             case STV_HIDDEN:
                h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-               (*bed->elf_backend_hide_symbol) (h);
+               (*bed->elf_backend_hide_symbol) (info, h);
                break;
              }
+
+         if (dt_needed && definition
+             && (h->elf_link_hash_flags
+                 & ELF_LINK_HASH_REF_REGULAR) != 0)
+           {
+             bfd_size_type oldsize;
+             bfd_size_type strindex;
+
+             /* The symbol from a DT_NEEDED object is referenced from
+                the regular object to create a dynamic executable. We
+                have to make sure there is a DT_NEEDED entry for it.  */
+
+             dt_needed = false;
+             oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+             strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+                                            elf_dt_soname (abfd),
+                                            true, false);
+             if (strindex == (bfd_size_type) -1)
+               goto error_return;
+
+             if (oldsize
+                 == _bfd_stringtab_size (elf_hash_table (info)->dynstr))
+               {
+                 asection *sdyn;
+                 Elf_External_Dyn *dyncon, *dynconend;
+
+                 sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+                                                 ".dynamic");
+                 BFD_ASSERT (sdyn != NULL);
+
+                 dyncon = (Elf_External_Dyn *) sdyn->contents;
+                 dynconend = (Elf_External_Dyn *) (sdyn->contents +
+                                                   sdyn->_raw_size);
+                 for (; dyncon < dynconend; dyncon++)
+                   {
+                     Elf_Internal_Dyn dyn;
+
+                     elf_swap_dyn_in (elf_hash_table (info)->dynobj,
+                                      dyncon, &dyn);
+                     BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
+                                 dyn.d_un.d_val != strindex);
+                   }
+               }
+
+             if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+               goto error_return;
+           }
        }
     }
 
@@ -2037,6 +2166,18 @@ elf_link_add_object_symbols (abfd, info)
        }
     }
 
+  if (! info->relocateable && ! dynamic)
+    {
+      asection *s;
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       if ((s->flags & SEC_MERGE)
+           && ! _bfd_merge_section (abfd,
+                                    &elf_hash_table (info)->merge_info,
+                                    s, &elf_section_data (s)->merge_info))
+         goto error_return;
+    }
+
   return true;
 
  error_return:
@@ -2044,8 +2185,6 @@ elf_link_add_object_symbols (abfd, info)
     free (buf);
   if (dynbuf != NULL)
     free (dynbuf);
-  if (dynver != NULL)
-    free (dynver);
   if (extversym != NULL)
     free (extversym);
   return false;
@@ -2283,7 +2422,6 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
   return true;
 }
 \f
-
 /* Read and swap the relocs from the section indicated by SHDR.  This
    may be either a REL or a RELA section.  The relocations are
    translated into RELA relocations and stored in INTERNAL_RELOCS,
@@ -2327,7 +2465,7 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       Elf_Internal_Rel *irel;
 
       erel = (Elf_External_Rel *) external_relocs;
-      erelend = erel + shdr->sh_size / shdr->sh_entsize;
+      erelend = erel + NUM_SHDR_ENTRIES (shdr);
       irela = internal_relocs;
       irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
                               * sizeof (Elf_Internal_Rel)));
@@ -2357,7 +2495,7 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       BFD_ASSERT (shdr->sh_entsize == sizeof (Elf_External_Rela));
 
       erela = (Elf_External_Rela *) external_relocs;
-      erelaend = erela + shdr->sh_size / shdr->sh_entsize;
+      erelaend = erela + NUM_SHDR_ENTRIES (shdr);
       irela = internal_relocs;
       for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
        {
@@ -2407,7 +2545,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
     {
       size_t size;
 
-      size = (o->reloc_count * bed->s->int_rels_per_ext_rel 
+      size = (o->reloc_count * bed->s->int_rels_per_ext_rel
              * sizeof (Elf_Internal_Rela));
       if (keep_memory)
        internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
@@ -2433,11 +2571,11 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
                                          external_relocs,
                                          internal_relocs))
     goto error_return;
-  if (!elf_link_read_relocs_from_section 
-      (abfd, 
+  if (!elf_link_read_relocs_from_section
+      (abfd,
        elf_section_data (o)->rel_hdr2,
        ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
-       internal_relocs + (rel_hdr->sh_size / rel_hdr->sh_entsize
+       internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr)
                          * bed->s->int_rels_per_ext_rel)))
     goto error_return;
 
@@ -2461,7 +2599,6 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
   return NULL;
 }
 \f
-
 /* Record an assignment to a symbol made by a linker script.  We need
    this in case some dynamic object refers to this symbol.  */
 
@@ -2768,7 +2905,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
-      bfd_size_type strsize;
+      asection *dynstr;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
@@ -2786,6 +2923,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
            return false;
+         info->flags |= DF_SYMBOLIC;
        }
 
       if (rpath != NULL)
@@ -2795,7 +2933,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
                                     true, true);
          if (indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_RPATH, indx))
+             || ! elf_add_dynamic_entry (info, DT_RPATH, indx)
+             || (info->new_dtags
+                 && ! elf_add_dynamic_entry (info, DT_RUNPATH, indx)))
            return false;
        }
 
@@ -2826,14 +2966,13 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            }
        }
 
+      eif.info = info;
+      eif.failed = false;
+
       /* If we are supposed to export all symbols into the dynamic symbol
          table (this is not the normal case), then do so.  */
       if (export_dynamic)
        {
-         struct elf_info_failed eif;
-
-         eif.failed = false;
-         eif.info = info;
          elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
                                  (PTR) &eif);
          if (eif.failed)
@@ -2855,8 +2994,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
-      eif.failed = false;
-      eif.info = info;
       elf_link_hash_traverse (elf_hash_table (info),
                              elf_adjust_dynamic_symbol,
                              (PTR) &eif);
@@ -2870,7 +3007,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       /* If there are initialization and/or finalization functions to
         call then add the corresponding DT_INIT/DT_FINI entries.  */
       h = (info->init_function
-          ? elf_link_hash_lookup (elf_hash_table (info), 
+          ? elf_link_hash_lookup (elf_hash_table (info),
                                   info->init_function, false,
                                   false, false)
           : NULL);
@@ -2882,7 +3019,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
       h = (info->fini_function
-          ? elf_link_hash_lookup (elf_hash_table (info), 
+          ? elf_link_hash_lookup (elf_hash_table (info),
                                   info->fini_function, false,
                                   false, false)
           : NULL);
@@ -2894,14 +3031,24 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
 
-      strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
-      if (! elf_add_dynamic_entry (info, DT_HASH, 0)
-         || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
-         || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
-         || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
-         || ! elf_add_dynamic_entry (info, DT_SYMENT,
-                                     sizeof (Elf_External_Sym)))
-       return false;
+      dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
+      /* If .dynstr is excluded from the link, we don't want any of
+        these tags.  Strictly, we should be checking each section
+        individually;  This quick check covers for the case where
+        someone does a /DISCARD/ : { *(*) }.  */
+      if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
+       {
+         bfd_size_type strsize;
+
+         strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+         if (! elf_add_dynamic_entry (info, DT_HASH, 0)
+             || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
+             || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
+             || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
+             || ! elf_add_dynamic_entry (info, DT_SYMENT,
+                                         sizeof (Elf_External_Sym)))
+           return false;
+       }
     }
 
   /* The backend must work out the sizes of all the other dynamic
@@ -2915,7 +3062,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       size_t dynsymcount;
       asection *s;
       size_t bucketcount = 0;
-      Elf_Internal_Sym isym;
       size_t hash_entry_size;
 
       /* Set up the version definition section.  */
@@ -2984,7 +3130,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              const char *name;
              bfd_size_type indx;
 
-             name = output_bfd->filename;
+             name = basename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
                                            name, true, false);
@@ -3084,6 +3230,22 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
+      if (info->new_dtags && info->flags)
+       {
+         if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
+           return false;
+       }
+
+      if (info->flags_1)
+       {
+         if (! info->shared)
+           info->flags_1 &= ~ (DF_1_INITFIRST
+                               | DF_1_NODELETE
+                               | DF_1_NOOPEN);
+         if (! elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
+           return false;
+       }
+
       /* Work out the size of the version reference section.  */
 
       s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
@@ -3152,7 +3314,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                                             true, false);
                else
                  indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                            t->vn_bfd->filename, true, false);
+                                            basename (t->vn_bfd->filename),
+                                            true, false);
                if (indx == (bfd_size_type) -1)
                  return false;
                t->vn_file = indx;
@@ -3194,7 +3357,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          }
       }
 
-      /* Assign dynsym indicies.  In a shared library we generate a 
+      /* Assign dynsym indicies.  In a shared library we generate a
         section symbol for each output section, which come first.
         Next come all of the back-end allocated local dynamic syms,
         followed by the rest of the global symbols.  */
@@ -3236,15 +3399,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (s->contents == NULL && s->_raw_size != 0)
        return false;
 
-      /* The first entry in .dynsym is a dummy symbol.  */
-      isym.st_value = 0;
-      isym.st_size = 0;
-      isym.st_name = 0;
-      isym.st_info = 0;
-      isym.st_other = 0;
-      isym.st_shndx = 0;
-      elf_swap_symbol_out (output_bfd, &isym,
-                          (PTR) (Elf_External_Sym *) s->contents);
+      if (dynsymcount != 0)
+       {
+         Elf_Internal_Sym isym;
+
+         /* The first entry in .dynsym is a dummy symbol.  */
+         isym.st_value = 0;
+         isym.st_size = 0;
+         isym.st_name = 0;
+         isym.st_info = 0;
+         isym.st_other = 0;
+         isym.st_shndx = 0;
+         elf_swap_symbol_out (output_bfd, &isym,
+                              (PTR) (Elf_External_Sym *) s->contents);
+       }
 
       /* Compute the size of the hashing table.  As a side effect this
         computes the hash values for all the names we export.  */
@@ -3260,7 +3428,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       memset (s->contents, 0, (size_t) s->_raw_size);
 
       bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
-      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, 
+      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
               s->contents + hash_entry_size);
 
       elf_hash_table (info)->bucketcount = bucketcount;
@@ -3293,6 +3461,9 @@ elf_fix_symbol_flags (h, eif)
      an ELF dynamic object.  */
   if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
     {
+      while (h->root.type == bfd_link_hash_indirect)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
       if (h->root.type != bfd_link_hash_defined
          && h->root.type != bfd_link_hash_defweak)
        h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
@@ -3354,16 +3525,24 @@ elf_fix_symbol_flags (h, eif)
   /* If -Bsymbolic was used (which means to bind references to global
      symbols to the definition within the shared object), and this
      symbol was defined in a regular object, then it actually doesn't
-     need a PLT entry.  Likewise, if the symbol has any kind of
-     visibility (internal, hidden, or protected), it doesn't need a
-     PLT.  */
+     need a PLT entry, and we can accomplish that by forcing it local.
+     Likewise, if the symbol has hidden or internal visibility.
+     FIXME: It might be that we also do not need a PLT for other
+     non-hidden visibilities, but we would have to tell that to the
+     backend specifically; we can't just clear PLT-related data here.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
       && eif->info->shared
-      && (eif->info->symbolic || ELF_ST_VISIBILITY (h->other))
+      && (eif->info->symbolic
+         || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+         || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     {
-      h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-      h->plt.offset = (bfd_vma) -1;
+      struct elf_backend_data *bed;
+      bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
+      if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+         || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+       h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      (*bed->elf_backend_hide_symbol) (eif->info, h);
     }
 
   /* If this is a weak defined symbol in a dynamic object, and we know
@@ -3708,7 +3887,7 @@ elf_link_assign_sym_version (h, data)
                              && ! sinfo->export_dynamic)
                            {
                              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                             (*bed->elf_backend_hide_symbol) (h);
+                             (*bed->elf_backend_hide_symbol) (info, h);
                              /* FIXME: The name of the symbol has
                                 already been recorded in the dynamic
                                 string table section.  */
@@ -3732,7 +3911,7 @@ elf_link_assign_sym_version (h, data)
          int version_index;
 
          /* If we aren't going to export this symbol, we don't need
-             to worry about it. */
+             to worry about it.  */
          if (h->dynindx == -1)
            return true;
 
@@ -3820,7 +3999,7 @@ elf_link_assign_sym_version (h, data)
                          && ! sinfo->export_dynamic)
                        {
                          h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                         (*bed->elf_backend_hide_symbol) (h);
+                         (*bed->elf_backend_hide_symbol) (info, h);
                          /* FIXME: The name of the symbol has already
                             been recorded in the dynamic string table
                             section.  */
@@ -3842,7 +4021,7 @@ elf_link_assign_sym_version (h, data)
              && ! sinfo->export_dynamic)
            {
              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-             (*bed->elf_backend_hide_symbol) (h);
+             (*bed->elf_backend_hide_symbol) (info, h);
              /* FIXME: The name of the symbol has already been
                 recorded in the dynamic string table section.  */
            }
@@ -3903,6 +4082,8 @@ static boolean elf_link_flush_output_syms
   PARAMS ((struct elf_final_link_info *));
 static boolean elf_link_output_extsym
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_sec_merge_syms
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_link_input_bfd
   PARAMS ((struct elf_final_link_info *, bfd *));
 static boolean elf_reloc_link_order
@@ -3940,11 +4121,13 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
   rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
 
   /* The contents field must last into write_object_contents, so we
-     allocate it with bfd_alloc rather than malloc.  */
-  rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+     allocate it with bfd_alloc rather than malloc.  Also since we
+     cannot be sure that the contents will actually be filled in,
+     we zero the allocated space.  */
+  rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size);
   if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
     return false;
-  
+
   /* We only allocate one set of hash entries, so we only do it the
      first time we are called.  */
   if (elf_section_data (o)->rel_hashes == NULL)
@@ -3977,6 +4160,7 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
      struct elf_link_hash_entry **rel_hash;
 {
   unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   for (i = 0; i < count; i++, rel_hash++)
     {
@@ -3989,26 +4173,38 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
        {
          Elf_External_Rel *erel;
          Elf_Internal_Rel irel;
-         
+
          erel = (Elf_External_Rel *) rel_hdr->contents + i;
-         elf_swap_reloc_in (abfd, erel, &irel);
+         if (bed->s->swap_reloc_in)
+           (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &irel);
+         else
+           elf_swap_reloc_in (abfd, erel, &irel);
          irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
                                    ELF_R_TYPE (irel.r_info));
-         elf_swap_reloc_out (abfd, &irel, erel);
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (abfd, &irel, (bfd_byte *) erel);
+         else
+           elf_swap_reloc_out (abfd, &irel, erel);
        }
       else
        {
          Elf_External_Rela *erela;
          Elf_Internal_Rela irela;
-         
+
          BFD_ASSERT (rel_hdr->sh_entsize
                      == sizeof (Elf_External_Rela));
-         
+
          erela = (Elf_External_Rela *) rel_hdr->contents + i;
-         elf_swap_reloca_in (abfd, erela, &irela);
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, &irela);
+         else
+           elf_swap_reloca_in (abfd, erela, &irela);
          irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
                                     ELF_R_TYPE (irela.r_info));
-         elf_swap_reloca_out (abfd, &irela, erela);
+         if (bed->s->swap_reloca_out)
+           (*bed->s->swap_reloca_out) (abfd, &irela, (bfd_byte *) erela);
+         else
+           elf_swap_reloca_out (abfd, &irela, erela);
        }
     }
 }
@@ -4037,6 +4233,7 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
+  boolean merged;
 
   if (info->shared)
     abfd->flags |= DYNAMIC;
@@ -4082,6 +4279,7 @@ elf_bfd_final_link (abfd, info)
   max_external_reloc_size = 0;
   max_internal_reloc_count = 0;
   max_sym_count = 0;
+  merged = false;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     {
       o->reloc_count = 0;
@@ -4103,6 +4301,9 @@ elf_bfd_final_link (abfd, info)
                 the linker has decided to not include.  */
              sec->linker_mark = true;
 
+             if (sec->flags & SEC_MERGE)
+               merged = true;
+
              if (info->relocateable || info->emitrelocations)
                o->reloc_count += sec->reloc_count;
 
@@ -4160,6 +4361,10 @@ elf_bfd_final_link (abfd, info)
        o->vma = 0;
     }
 
+  if (! info->relocateable && merged)
+    elf_link_hash_traverse (elf_hash_table (info),
+                           elf_link_sec_merge_syms, (PTR) abfd);
+
   /* Figure out the file positions for everything but the symbol table
      and the relocs.  We set symcount to force assign_section_numbers
      to create a symbol table.  */
@@ -4188,9 +4393,9 @@ elf_bfd_final_link (abfd, info)
          if (output_section != NULL
              && (o->flags & SEC_RELOC) != 0)
            {
-             struct bfd_elf_section_data *esdi 
+             struct bfd_elf_section_data *esdi
                = elf_section_data (o);
-             struct bfd_elf_section_data *esdo 
+             struct bfd_elf_section_data *esdo
                = elf_section_data (output_section);
              unsigned int *rel_count;
              unsigned int *rel_count2;
@@ -4207,12 +4412,10 @@ elf_bfd_final_link (abfd, info)
                  rel_count = &esdo->rel_count2;
                  rel_count2 = &esdo->rel_count;
                }
-             
-             *rel_count += (esdi->rel_hdr.sh_size 
-                            / esdi->rel_hdr.sh_entsize);
+
+             *rel_count += NUM_SHDR_ENTRIES (& esdi->rel_hdr);
              if (esdi->rel_hdr2)
-               *rel_count2 += (esdi->rel_hdr2->sh_size 
-                               / esdi->rel_hdr2->sh_entsize);
+               *rel_count2 += NUM_SHDR_ENTRIES (esdi->rel_hdr2);
            }
        }
 
@@ -4235,7 +4438,7 @@ elf_bfd_final_link (abfd, info)
        }
 
       /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
-        to count upwards while actually outputting the relocations. */
+        to count upwards while actually outputting the relocations.  */
       elf_section_data (o)->rel_count = 0;
       elf_section_data (o)->rel_count2 = 0;
     }
@@ -4257,7 +4460,7 @@ elf_bfd_final_link (abfd, info)
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
   /* sh_offset is set just below.  */
-  symtab_hdr->sh_addralign = 4;  /* FIXME: system dependent?  */
+  symtab_hdr->sh_addralign = bed->s->file_align;
 
   off = elf_tdata (abfd)->next_file_pos;
   off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true);
@@ -4323,7 +4526,7 @@ elf_bfd_final_link (abfd, info)
          if (o != NULL)
            o->target_index = bfd_get_symcount (abfd);
          elfsym.st_shndx = i;
-         if (info->relocateable || info->emitrelocations || o == NULL)
+         if (info->relocateable || o == NULL)
            elfsym.st_value = 0;
          else
            elfsym.st_value = o->vma;
@@ -4414,7 +4617,7 @@ elf_bfd_final_link (abfd, info)
   /* That wrote out all the local symbols.  Finish up the symbol table
      with the global symbols. Even if we want to strip everything we
      can, we still need to deal with those global symbols that got
-     converted to local in a version script. */
+     converted to local in a version script.  */
 
   if (info->shared)
     {
@@ -4436,7 +4639,8 @@ elf_bfd_final_link (abfd, info)
   /* The sh_info field records the index of the first non local symbol.  */
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
-  if (dynamic)
+  if (dynamic
+      && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
       Elf_External_Sym *dynsym =
@@ -4526,7 +4730,7 @@ elf_bfd_final_link (abfd, info)
                            Elf_Internal_Sym *, asection *)))
               elf_link_output_sym))
        return false;
-    }      
+    }
 
   /* Flush all symbols to the file.  */
   if (! elf_link_flush_output_syms (&finfo))
@@ -4565,13 +4769,13 @@ elf_bfd_final_link (abfd, info)
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, 
+      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
                              elf_section_data (o)->rel_count,
                              elf_section_data (o)->rel_hashes);
       if (elf_section_data (o)->rel_hdr2 != NULL)
        elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
                                elf_section_data (o)->rel_count2,
-                               (elf_section_data (o)->rel_hashes 
+                               (elf_section_data (o)->rel_hashes
                                 + elf_section_data (o)->rel_count));
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
@@ -4701,7 +4905,8 @@ elf_bfd_final_link (abfd, info)
       for (o = dynobj->sections; o != NULL; o = o->next)
        {
          if ((o->flags & SEC_HAS_CONTENTS) == 0
-             || o->_raw_size == 0)
+             || o->_raw_size == 0
+             || o->output_section == bfd_abs_section_ptr)
            continue;
          if ((o->flags & SEC_LINKER_CREATED) == 0)
            {
@@ -4877,6 +5082,33 @@ elf_link_flush_output_syms (finfo)
   return true;
 }
 
+/* Adjust all external symbols pointing into SEC_MERGE sections
+   to reflect the object merging within the sections.  */
+
+static boolean
+elf_link_sec_merge_syms (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  asection *sec;
+
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
+      && elf_section_data (sec)->merge_info)
+    {
+      bfd *output_bfd = (bfd *) data;
+
+      h->root.u.def.value =
+       _bfd_merged_section_offset (output_bfd,
+                                   &h->root.u.def.section,
+                                   elf_section_data (sec)->merge_info,
+                                   h->root.u.def.value, (bfd_vma) 0);
+    }
+
+  return true;
+}
+
 /* Add an external symbol to the symbol table.  This is called from
    the hash table traversal routine.  When generating a shared object,
    we go through the symbol table twice.  The first time we output
@@ -4915,6 +5147,7 @@ elf_link_output_extsym (h, data)
      referenced by regular files, because we will already have issued
      warnings for them.  */
   if (! finfo->info->relocateable
+      && ! finfo->info->allow_shlib_undefined
       && ! (finfo->info->shared
            && !finfo->info->no_undefined)
       && h->root.type == bfd_link_hash_undefined
@@ -5034,12 +5267,9 @@ elf_link_output_extsym (h, data)
          symbol foo@@GNU_1.2 is the default, which should be used when
          foo is used with no version, then we add an indirect symbol
          foo which points to foo@@GNU_1.2.  We ignore these symbols,
-         since the indirected symbol is already in the hash table.  If
-         the indirect symbol is non-ELF, fall through and output it.  */
-      if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) == 0)
-       return true;
+         since the indirected symbol is already in the hash table.  */
+      return true;
 
-      /* Fall through.  */
     case bfd_link_hash_warning:
       /* We can't represent these symbols in ELF, although a warning
          symbol may have come from a .gnu.warning.SYMBOL section.  We
@@ -5089,6 +5319,11 @@ elf_link_output_extsym (h, data)
       sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
     }
 
+  /* If a symbol is not defined locally, we clear the visibility
+     field.  */
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+    sym.st_other ^= ELF_ST_VISIBILITY(sym.st_other);
+
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We have already know the symbol index.  We also fill
      in the entry in the .hash section.  */
@@ -5110,7 +5345,7 @@ elf_link_output_extsym (h, data)
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
-      hash_entry_size 
+      hash_entry_size
        = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
       bucketpos = ((bfd_byte *) finfo->hash_sec->contents
                   + (bucket + 2) * hash_entry_size);
@@ -5170,7 +5405,7 @@ elf_link_output_extsym (h, data)
    OUTPUT_BFD.  */
 
 static void
-elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, 
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
                        internal_relocs)
      bfd *output_bfd;
      asection *input_section;
@@ -5182,11 +5417,12 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
   Elf_Internal_Shdr *output_rel_hdr;
   asection *output_section;
   unsigned int *rel_countp = NULL;
+  struct elf_backend_data *bed;
 
   output_section = input_section->output_section;
   output_rel_hdr = NULL;
 
-  if (elf_section_data (output_section)->rel_hdr.sh_entsize 
+  if (elf_section_data (output_section)->rel_hdr.sh_entsize
       == input_rel_hdr->sh_entsize)
     {
       output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
@@ -5201,9 +5437,10 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
     }
 
   BFD_ASSERT (output_rel_hdr != NULL);
-  
+
+  bed = get_elf_backend_data (output_bfd);
   irela = internal_relocs;
-  irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+  irelaend = irela + NUM_SHDR_ENTRIES (input_rel_hdr);
   if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
     {
       Elf_External_Rel *erel;
@@ -5216,7 +5453,10 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
          irel.r_offset = irela->r_offset;
          irel.r_info = irela->r_info;
          BFD_ASSERT (irela->r_addend == 0);
-         elf_swap_reloc_out (output_bfd, &irel, erel);
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (output_bfd, &irel, (PTR) erel);
+         else
+           elf_swap_reloc_out (output_bfd, &irel, erel);
        }
     }
   else
@@ -5227,12 +5467,15 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
                  == sizeof (Elf_External_Rela));
       erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
       for (; irela < irelaend; irela++, erela++)
-       elf_swap_reloca_out (output_bfd, irela, erela);
+       if (bed->s->swap_reloca_out)
+         (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela);
+       else
+         elf_swap_reloca_out (output_bfd, irela, erela);
     }
 
   /* Bump the counter, so that we know where to add the next set of
      relocations.  */
-  *rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+  *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr);
 }
 
 /* Link an input file into the linker output file.  This function
@@ -5324,14 +5567,32 @@ elf_link_input_bfd (finfo, input_bfd)
            }
        }
 
+      name = NULL;
       if (isym->st_shndx == SHN_UNDEF)
-       isec = bfd_und_section_ptr;
+        {
+         isec = bfd_und_section_ptr;
+         name = isec->name;
+       }
       else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
-       isec = section_from_elf_index (input_bfd, isym->st_shndx);
+       {
+         isec = section_from_elf_index (input_bfd, isym->st_shndx);
+         if (isec && elf_section_data (isec)->merge_info
+             && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+           isym->st_value =
+             _bfd_merged_section_offset (output_bfd, &isec,
+                                         elf_section_data (isec)->merge_info,
+                                         isym->st_value, (bfd_vma) 0);
+       }
       else if (isym->st_shndx == SHN_ABS)
-       isec = bfd_abs_section_ptr;
+       {
+         isec = bfd_abs_section_ptr;
+         name = isec->name;
+       }
       else if (isym->st_shndx == SHN_COMMON)
-       isec = bfd_com_section_ptr;
+       {
+         isec = bfd_com_section_ptr;
+         name = isec->name;
+       }
       else
        {
          /* Who knows?  */
@@ -5344,16 +5605,54 @@ elf_link_input_bfd (finfo, input_bfd)
       if (esym == external_syms)
        continue;
 
+      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+       {
+         asection *ksec;
+
+         /* Save away all section symbol values.  */
+         if (isec != NULL)
+           {
+             if (name)
+               {
+                 if (isec->symbol->value != isym->st_value)
+                   (*_bfd_error_handler)
+                     (_("%s: invalid section symbol index 0x%x (%s) ingored"),
+                      bfd_get_filename (input_bfd), isym->st_shndx,
+                      name);
+                 continue;
+               }
+             isec->symbol->value = isym->st_value;
+           }
+
+         /* If this is a discarded link-once section symbol, update
+            it's value to that of the kept section symbol.  The
+            linker will keep the first of any matching link-once
+            sections, so we should have already seen it's section
+            symbol.  I trust no-one will have the bright idea of
+            re-ordering the bfd list...  */
+         if (isec != NULL
+             && (bfd_get_section_flags (input_bfd, isec) & SEC_LINK_ONCE) != 0
+             && (ksec = isec->kept_section) != NULL)
+           {
+             isym->st_value = ksec->symbol->value;
+
+             /* That put the value right, but the section info is all
+                wrong.  I hope this works.  */
+             isec->output_offset = ksec->output_offset;
+             isec->output_section = ksec->output_section;
+           }
+
+         /* We never output section symbols.  Instead, we use the
+            section symbol of the corresponding section in the output
+            file.  */
+         continue;
+       }
+
       /* If we are stripping all symbols, we don't want to output this
         one.  */
       if (finfo->info->strip == strip_all)
        continue;
 
-      /* We never output section symbols.  Instead, we use the section
-        symbol of the corresponding section in the output file.  */
-      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
-       continue;
-
       /* If we are discarding all local symbols, we don't want to
         output this one.  If we are generating a relocateable output
         file, then some of the local symbols may be required by
@@ -5385,7 +5684,9 @@ elf_link_input_bfd (finfo, input_bfd)
       if ((finfo->info->strip == strip_some
           && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
               == NULL))
-         || (finfo->info->discard == discard_l
+         || (((finfo->info->discard == discard_sec_merge
+               && (isec->flags & SEC_MERGE) && ! finfo->info->relocateable)
+              || finfo->info->discard == discard_l)
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
 
@@ -5501,7 +5802,7 @@ elf_link_input_bfd (finfo, input_bfd)
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
-             irelaend = 
+             irelaend =
                irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
                          + elf_section_data (o->output_section)->rel_count
@@ -5514,6 +5815,10 @@ elf_link_input_bfd (finfo, input_bfd)
 
                  irela->r_offset += o->output_offset;
 
+                 /* Relocs in an executable have to be virtual addresses.  */
+                 if (finfo->info->emitrelocations)
+                   irela->r_offset += o->output_section->vma;
+
                  r_symndx = ELF_R_SYM (irela->r_info);
 
                  if (r_symndx == 0)
@@ -5550,7 +5855,7 @@ elf_link_input_bfd (finfo, input_bfd)
                      continue;
                    }
 
-                 /* This is a reloc against a local symbol. */
+                 /* This is a reloc against a local symbol.  */
 
                  *rel_hash = NULL;
                  isym = finfo->internal_syms + r_symndx;
@@ -5629,21 +5934,33 @@ elf_link_input_bfd (finfo, input_bfd)
 
              /* Swap out the relocs.  */
              input_rel_hdr = &elf_section_data (o)->rel_hdr;
-             elf_link_output_relocs (output_bfd, o, 
+             elf_link_output_relocs (output_bfd, o,
                                      input_rel_hdr,
                                      internal_relocs);
-             internal_relocs 
-               += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+             internal_relocs += NUM_SHDR_ENTRIES (input_rel_hdr);
              input_rel_hdr = elf_section_data (o)->rel_hdr2;
              if (input_rel_hdr)
-               elf_link_output_relocs (output_bfd, o, 
+               elf_link_output_relocs (output_bfd, o,
                                        input_rel_hdr,
                                        internal_relocs);
            }
        }
 
       /* Write out the modified section contents.  */
-      if (elf_section_data (o)->stab_info == NULL)
+      if (elf_section_data (o)->stab_info)
+       {
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
+                 o, &elf_section_data (o)->stab_info, contents)))
+           return false;
+       }
+      else if (elf_section_data (o)->merge_info)
+       {
+         if (! (_bfd_write_merged_section
+                (output_bfd, o, elf_section_data (o)->merge_info)))
+           return false;
+       }
+      else
        {
          if (! (o->flags & SEC_EXCLUDE) &&
              ! bfd_set_section_contents (output_bfd, o->output_section,
@@ -5653,13 +5970,6 @@ elf_link_input_bfd (finfo, input_bfd)
                                           : o->_raw_size)))
            return false;
        }
-      else
-       {
-         if (! (_bfd_write_section_stabs
-                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
-                 o, &elf_section_data (o)->stab_info, contents)))
-           return false;
-       }
     }
 
   return true;
@@ -5683,6 +5993,7 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
   bfd_vma addend;
   struct elf_link_hash_entry **rel_hash_ptr;
   Elf_Internal_Shdr *rel_hdr;
+  struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
@@ -5806,7 +6117,10 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irel.r_info = ELF_R_INFO (indx, howto->type);
       erel = ((Elf_External_Rel *) rel_hdr->contents
              + elf_section_data (output_section)->rel_count);
-      elf_swap_reloc_out (output_bfd, &irel, erel);
+      if (bed->s->swap_reloc_out)
+       (*bed->s->swap_reloc_out) (output_bfd, &irel, (bfd_byte *) erel);
+      else
+       elf_swap_reloc_out (output_bfd, &irel, erel);
     }
   else
     {
@@ -5818,14 +6132,16 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irela.r_addend = addend;
       erela = ((Elf_External_Rela *) rel_hdr->contents
               + elf_section_data (output_section)->rel_count);
-      elf_swap_reloca_out (output_bfd, &irela, erela);
+      if (bed->s->swap_reloca_out)
+       (*bed->s->swap_reloca_out) (output_bfd, &irela, (bfd_byte *) erela);
+      else
+       elf_swap_reloca_out (output_bfd, &irela, erela);
     }
 
   ++elf_section_data (output_section)->rel_count;
 
   return true;
 }
-
 \f
 /* Allocate a pointer to live in a linker created section.  */
 
@@ -5948,7 +6264,6 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
 
   return true;
 }
-
 \f
 #if ARCH_SIZE==64
 #define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR)
@@ -6175,22 +6490,22 @@ elf_gc_mark (info, sec, gc_mark_hook)
            {
              elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
              if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
-               rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+               rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
              else
                {
                  h = sym_hashes[r_symndx - extsymoff];
-                 rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+                 rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
                }
            }
          else if (r_symndx >= nlocsyms)
            {
              h = sym_hashes[r_symndx - extsymoff];
-             rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+             rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
            }
          else
            {
              elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
-             rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+             rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
            }
 
          if (rsec && !rsec->gc_mark)
@@ -6261,7 +6576,7 @@ elf_gc_sweep (info, gc_sweep_hook)
              if (internal_relocs == NULL)
                return false;
 
-             r = (*gc_sweep_hook)(o->owner, info, o, internal_relocs);
+             r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
 
              if (!info->keep_memory)
                free (internal_relocs);
@@ -6314,7 +6629,7 @@ elf_gc_propagate_vtable_entries_used (h, okp)
      struct elf_link_hash_entry *h;
      PTR okp;
 {
-  /* Those that are not vtables. */
+  /* Those that are not vtables.  */
   if (h->vtable_parent == NULL)
     return true;
 
@@ -6556,7 +6871,7 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
       if (ptr)
        {
          ptr = bfd_realloc (ptr - 1, bytes);
-         
+
          if (ptr != NULL)
            {
              size_t oldbytes;
@@ -6570,12 +6885,12 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
 
       if (ptr == NULL)
        return false;
-      
+
       /* And arrange for that done flag to be at index -1.  */
       h->vtable_entries_used = ptr + 1;
       h->vtable_entries_size = size;
     }
-  
+
   h->vtable_entries_used[addend / FILE_ALIGN] = true;
 
   return true;
This page took 0.057299 seconds and 4 git commands to generate.