* section.c (_bfd_strip_section_from_output): Add info parameter.
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 91b7b67c42ece4c5f55a081a96aa1af4f6732449..ce71d948c43f894a8357428221f3422d004899f4 100644 (file)
@@ -48,18 +48,17 @@ static boolean elf_link_find_version_dependencies
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_link_assign_sym_version
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_renumber_dynsyms
-  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 
   PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
-static void elf_link_remove_section_and_adjust_dynindices 
-  PARAMS ((struct bfd_link_info *, asection *));
 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, 
+          struct elf_link_hash_entry **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -81,6 +80,138 @@ elf_bfd_link_add_symbols (abfd, info)
     }
 }
 \f
+/* Return true iff this is a non-common definition of a symbol.  */
+static boolean
+is_global_symbol_definition (abfd, sym)
+     bfd * abfd;
+     Elf_Internal_Sym * sym;
+{
+  /* Local symbols do not count, but target specific ones might.  */
+  if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+      && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+    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)
+    return false;
+
+  /* If the symbol is in a target specific section then we
+     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
+   the symbol is defined in this element.  */
+static boolean
+elf_link_is_defined_archive_symbol (abfd, symdef)
+     bfd * abfd;
+     carsym * symdef;
+{
+  Elf_Internal_Shdr * hdr;
+  Elf_External_Sym *  esym;
+  Elf_External_Sym *  esymend;
+  Elf_External_Sym *  buf = NULL;
+  size_t symcount;
+  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;
+
+  if (! bfd_check_format (abfd, bfd_object))
+    return false;
+
+  /* If we have already included the element containing this symbol in the
+     link then we do not need to include it again.  Just claim that any symbol
+     it contains is not a definition, so that our caller will not decide to
+     (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;
+  else
+    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+  /* The sh_info field of the symtab header tells us where the
+     external symbols start.  We don't care about the local symbols.  */
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
+
+  buf = ((Elf_External_Sym *)
+        bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+  if (buf == NULL && extsymcount != 0)
+    return false;
+
+  /* Read in the symbol table.
+     FIXME:  This ought to be cached somewhere.  */
+  if (bfd_seek (abfd,
+               hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+               SEEK_SET) != 0
+      || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+         != extsymcount * sizeof (Elf_External_Sym)))
+    {
+      free (buf);
+      return false;
+    }
+
+  /* Scan the symbol table looking for SYMDEF.  */
+  esymend = buf + extsymcount;
+  for (esym = buf;
+       esym < esymend;
+       esym++)
+    {
+      Elf_Internal_Sym sym;
+      const char * name;
+
+      elf_swap_symbol_in (abfd, esym, & sym);
+
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      if (name == (const char *) NULL)
+       break;
+
+      if (strcmp (name, symdef->name) == 0)
+       {
+         result = is_global_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
@@ -201,7 +332,24 @@ elf_link_add_archive_symbols (abfd, info)
          if (h == NULL)
            continue;
 
-         if (h->root.type != bfd_link_hash_undefined)
+         if (h->root.type == bfd_link_hash_common)
+           {
+             /* We currently have a common symbol.  The archive map contains
+                a reference to this symbol, so we may want to include it.  We
+                only want to include it however, if this archive element
+                contains a definition of the symbol, not just another common
+                declaration of it.
+
+                Unfortunately some archivers (including GNU ar) will put
+                declarations of common symbols into their archive maps, as
+                well as real definitions, so we cannot just go by the archive
+                map alone.  Instead we must read in the element's symbol
+                table and check that to see what kind of symbol definition
+                this is.  */
+             if (! elf_link_is_defined_archive_symbol (abfd, symdef))
+               continue;
+           }
+         else if (h->root.type != bfd_link_hash_undefined)
            {
              if (h->root.type != bfd_link_hash_undefweak)
                defined[i] = true;
@@ -366,6 +514,17 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
       break;
     }
 
+  /* In cases involving weak versioned symbols, we may wind up trying
+     to merge a symbol with itself.  Catch that here, to avoid the
+     confusion that results if we try to override a symbol with
+     itself.  The additional tests catch cases like
+     _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
+     dynamic object, which we do want to handle here.  */
+  if (abfd == oldbfd
+      && ((abfd->flags & DYNAMIC) == 0
+         || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
+    return true;
+
   /* NEWDYN and OLDDYN indicate whether the new or old symbol,
      respectively, is from a dynamic object.  */
 
@@ -374,10 +533,35 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   else
     newdyn = false;
 
-  if (oldbfd == NULL || (oldbfd->flags & DYNAMIC) == 0)
-    olddyn = false;
+  if (oldbfd != NULL)
+    olddyn = (oldbfd->flags & DYNAMIC) != 0;
   else
-    olddyn = true;
+    {
+      asection *hsec;
+
+      /* This code handles the special SHN_MIPS_{TEXT,DATA} section
+         indices used by MIPS ELF.  */
+      switch (h->root.type)
+       {
+       default:
+         hsec = NULL;
+         break;
+
+       case bfd_link_hash_defined:
+       case bfd_link_hash_defweak:
+         hsec = h->root.u.def.section;
+         break;
+
+       case bfd_link_hash_common:
+         hsec = h->root.u.c.p->section;
+         break;
+       }
+
+      if (hsec == NULL)
+       olddyn = false;
+      else
+       olddyn = (hsec->symbol->flags & BSF_DYNAMIC) != 0;
+    }
 
   /* NEWDEF and OLDDEF indicate whether the new or old symbol,
      respectively, appear to be a definition rather than reference.  */
@@ -638,15 +822,29 @@ 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.  To make
-     this work we have to frob the flags.  */
+     case, we prefer the definition in the shared object.  */
   if (olddef
-      && ! olddyn
       && h->root.type == bfd_link_hash_defweak
       && newdef
       && newdyn
       && bind != STB_WEAK)
-    h->elf_link_hash_flags &= ~ ELF_LINK_HASH_DEF_REGULAR;
+    {
+      /* To make this work we have to frob the flags so that the rest
+         of the code does not think we are using the regular
+         definition.  */
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+      else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+      h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR
+                                  | ELF_LINK_HASH_DEF_DYNAMIC);
+
+      /* If H is the target of an indirection, we want the caller to
+         use H rather than the indirect symbol.  Otherwise if we are
+         defining a new indirect symbol we will wind up attaching it
+         to the entry we are overriding.  */
+      *sym_hash = h;
+    }
 
   /* Handle the special case of a non-weak definition in a shared
      object followed by a weak definition in a regular object.  In
@@ -909,6 +1107,23 @@ elf_link_add_object_symbols (abfd, info)
            goto error_return;
          link = elf_elfsections (abfd)[elfsec]->sh_link;
 
+         {
+           /* The shared libraries distributed with hpux11 have a bogus
+              sh_link field for the ".dynamic" section.  This code detects
+              when LINK refers to a section that is not a string table and
+              tries to find the string table for the ".dynsym" section
+              instead.  */
+           Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link];
+           if (hdr->sh_type != SHT_STRTAB)
+             {
+               asection *s = bfd_get_section_by_name (abfd, ".dynsym");
+               int elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+               if (elfsec == -1)
+                 goto error_return;
+               link = elf_elfsections (abfd)[elfsec]->sh_link;
+             }
+         }
+
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
          for (; extdyn < extdynend; extdyn++)
@@ -1351,9 +1566,24 @@ elf_link_add_object_symbols (abfd, info)
              h->type = ELF_ST_TYPE (sym.st_info);
            }
 
-         if (sym.st_other != 0
-             && (definition || h->other == 0))
-           h->other = sym.st_other;
+         /* If st_other has a processor-specific meaning, specific code
+            might be needed here.  */
+         if (sym.st_other != 0)
+           {
+             /* 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))
+               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.  */
+             if (!symvis && !hvis
+                 && (definition || h->other == 0))
+               h->other = sym.st_other;
+           }
 
          /* Set a flag in the hash table entry indicating the type of
             reference or definition we just found.  Keep a count of
@@ -1512,7 +1742,8 @@ elf_link_add_object_symbols (abfd, info)
                        (hi->elf_link_hash_flags
                         & (ELF_LINK_HASH_REF_DYNAMIC
                            | ELF_LINK_HASH_REF_REGULAR
-                           | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+                           | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                           | ELF_LINK_NON_GOT_REF));
 
                      /* Copy over the global and procedure linkage table
                         offset entries.  These may have been already set
@@ -1621,7 +1852,8 @@ elf_link_add_object_symbols (abfd, info)
                            (hi->elf_link_hash_flags
                             & (ELF_LINK_HASH_REF_DYNAMIC
                                | ELF_LINK_HASH_REF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+                               | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                               | ELF_LINK_NON_GOT_REF));
 
                          /* Copy over the global and procedure linkage
                              table offset entries.  These may have been
@@ -1980,16 +2212,18 @@ elf_link_create_dynamic_sections (abfd, info)
       && ! _bfd_elf_link_record_dynamic_symbol (info, h))
     return false;
 
+  bed = get_elf_backend_data (abfd);
+
   s = bfd_make_section (abfd, ".hash");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
     return false;
+  elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
 
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
-  bed = get_elf_backend_data (abfd);
   if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
     return false;
 
@@ -2032,6 +2266,76 @@ elf_add_dynamic_entry (info, tag, val)
 
   return true;
 }
+
+/* Record a new local dynamic symbol.  */
+
+boolean
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     long input_indx;
+{
+  struct elf_link_local_dynamic_entry *entry;
+  struct elf_link_hash_table *eht;
+  struct bfd_strtab_hash *dynstr;
+  Elf_External_Sym esym;
+  unsigned long dynstr_index;
+  char *name;
+
+  /* See if the entry exists already.  */
+  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+    if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+      return true;
+
+  entry = (struct elf_link_local_dynamic_entry *)
+    bfd_alloc (input_bfd, sizeof (*entry));
+  if (entry == NULL)
+    return false;
+
+  /* Go find the symbol, so that we can find it's name.  */
+  if (bfd_seek (input_bfd,
+               (elf_tdata (input_bfd)->symtab_hdr.sh_offset
+                + input_indx * sizeof (Elf_External_Sym)),
+               SEEK_SET) != 0
+      || (bfd_read (&esym, sizeof (Elf_External_Sym), 1, input_bfd)
+         != sizeof (Elf_External_Sym)))
+    return false;
+  elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+
+  name = (bfd_elf_string_from_elf_section
+         (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+          entry->isym.st_name));
+
+  dynstr = elf_hash_table (info)->dynstr;
+  if (dynstr == NULL)
+    {
+      /* Create a strtab to hold the dynamic symbol names.  */
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+      if (dynstr == NULL)
+       return false;
+    }
+
+  dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+  if (dynstr_index == (unsigned long) -1)
+    return false;
+  entry->isym.st_name = dynstr_index;
+
+  eht = elf_hash_table (info);
+
+  entry->next = eht->dynlocal;
+  eht->dynlocal = entry;
+  entry->input_bfd = input_bfd;
+  entry->input_indx = input_indx;
+  eht->dynsymcount++;
+
+  /* Whatever binding the symbol had before, it's now local.  */
+  entry->isym.st_info
+    = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
+
+  /* The dynindx will be set at the end of size_dynamic_sections.  */
+
+  return true;
+}
 \f
 
 /* Read and swap the relocs from the section indicated by SHDR.  This
@@ -2051,6 +2355,8 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
      PTR external_relocs;
      Elf_Internal_Rela *internal_relocs;
 {
+  struct elf_backend_data *bed;
+
   /* If there aren't any relocations, that's OK.  */
   if (!shdr)
     return true;
@@ -2064,24 +2370,36 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       != shdr->sh_size)
     return false;
 
+  bed = get_elf_backend_data (abfd);
+
   /* Convert the external relocations to the internal format.  */
   if (shdr->sh_entsize == sizeof (Elf_External_Rel))
     {
       Elf_External_Rel *erel;
       Elf_External_Rel *erelend;
       Elf_Internal_Rela *irela;
+      Elf_Internal_Rel *irel;
 
       erel = (Elf_External_Rel *) external_relocs;
       erelend = erel + shdr->sh_size / shdr->sh_entsize;
       irela = internal_relocs;
-      for (; erel < erelend; erel++, irela++)
+      irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
+                              * sizeof (Elf_Internal_Rel)));
+      for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel)
        {
-         Elf_Internal_Rel irel;
+         unsigned char i;
 
-         elf_swap_reloc_in (abfd, erel, &irel);
-         irela->r_offset = irel.r_offset;
-         irela->r_info = irel.r_info;
-         irela->r_addend = 0;
+         if (bed->s->swap_reloc_in)
+           (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
+         else
+           elf_swap_reloc_in (abfd, erel, irel);
+
+         for (i = 0; i < bed->s->int_rels_per_ext_rel; ++i)
+           {
+             irela[i].r_offset = irel[i].r_offset;
+             irela[i].r_info = irel[i].r_info;
+             irela[i].r_addend = 0;
+           }
        }
     }
   else
@@ -2095,8 +2413,13 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       erela = (Elf_External_Rela *) external_relocs;
       erelaend = erela + shdr->sh_size / shdr->sh_entsize;
       irela = internal_relocs;
-      for (; erela < erelaend; erela++, irela++)
-       elf_swap_reloca_in (abfd, erela, irela);
+      for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
+       {
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+         else
+           elf_swap_reloca_in (abfd, erela, irela);
+       }
     }
 
   return true;
@@ -2124,6 +2447,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
   Elf_Internal_Shdr *rel_hdr;
   PTR alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (elf_section_data (o)->relocs != NULL)
     return elf_section_data (o)->relocs;
@@ -2137,7 +2461,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
     {
       size_t size;
 
-      size = o->reloc_count * sizeof (Elf_Internal_Rela);
+      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);
       else
@@ -2166,7 +2491,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
       (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 + (rel_hdr->sh_size / rel_hdr->sh_entsize
+                         * bed->s->int_rels_per_ext_rel)))
     goto error_return;
 
   /* Cache the results for next time, if we can.  */
@@ -2196,7 +2522,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
 /*ARGSUSED*/
 boolean
 NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
      const char *name;
      boolean provide;
@@ -2232,7 +2558,10 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
     h->verinfo.verdef = NULL;
 
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-  h->type = STT_OBJECT;
+
+  /* When possible, keep the original type of the symbol */
+  if (h->type == STT_NOTYPE)
+    h->type = STT_OBJECT;
 
   if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0
@@ -2269,8 +2598,6 @@ struct elf_assign_sym_version_info
   struct bfd_elf_version_tree *verdefs;
   /* Whether we are exporting all dynamic symbols.  */
   boolean export_dynamic;
-  /* Whether we removed any symbols from the dynamic symbol table.  */
-  boolean removed_dynamic;
   /* Whether we had a failure.  */
   boolean failed;
 };
@@ -2315,7 +2642,7 @@ compute_bucket_count (info)
      struct bfd_link_info *info;
 {
   size_t dynsymcount = elf_hash_table (info)->dynsymcount;
-  size_t best_size;
+  size_t best_size = 0;
   unsigned long int *hashcodes;
   unsigned long int *hashcodesp;
   unsigned long int i;
@@ -2445,42 +2772,6 @@ compute_bucket_count (info)
   return best_size;
 }
 
-/* Remove SECTION from the BFD.  If a symbol for SECTION was going to
-   be put into the dynamic symbol table, remove it, and renumber
-   subsequent entries.  */
-
-static void
-elf_link_remove_section_and_adjust_dynindices (info, section)
-     struct bfd_link_info *info;
-     asection *section;
-{
-  /* Remove the section from the output list.  */
-  _bfd_strip_section_from_output (section);
-
-  if (elf_section_data (section->output_section)->dynindx)
-    {
-      asection *s;
-      int increment = -1;
-
-      /* We were going to output an entry in the dynamic symbol table
-        for the symbol corresponding to this section.  Now, the
-        section is gone.  So, we must renumber the dynamic indices of
-        all subsequent sections and all other entries in the dynamic
-        symbol table.  */
-      elf_section_data (section->output_section)->dynindx = 0;
-      for (s = section->output_section->next; s; s = s->next)
-       if (elf_section_data (s)->dynindx)
-         --elf_section_data (s)->dynindx;
-      
-      elf_link_hash_traverse (elf_hash_table (info),
-                             _bfd_elf_link_adjust_dynindx,
-                             &increment);
-
-      /* There is one less dynamic symbol than there was before.  */
-      --elf_hash_table (info)->dynsymcount;
-    }
-}
-
 /* Set up the sizes and contents of the ELF dynamic sections.  This is
    called by the ELF linker emulation before_allocation routine.  We
    must set the sizes of the sections before the linker sets the
@@ -2504,7 +2795,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   bfd_size_type soname_indx;
   bfd *dynobj;
   struct elf_backend_data *bed;
-  bfd_size_type old_dynsymcount;
   struct elf_assign_sym_version_info asvinfo;
 
   *sinterpptr = NULL;
@@ -2528,20 +2818,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (dynobj == NULL)
     return true;
 
-  /* 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)
-       return false;
-    }
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
@@ -2604,12 +2880,25 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            }
        }
 
+      /* 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)
+           return false;
+       }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
       asvinfo.verdefs = verdefs;
       asvinfo.export_dynamic = export_dynamic;
-      asvinfo.removed_dynamic = false;
       asvinfo.failed = false;
 
       elf_link_hash_traverse (elf_hash_table (info),
@@ -2671,7 +2960,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
-  old_dynsymcount = elf_hash_table (info)->dynsymcount;
   if (bed->elf_backend_size_dynamic_sections
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return false;
@@ -2682,6 +2970,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       asection *s;
       size_t bucketcount = 0;
       Elf_Internal_Sym isym;
+      size_t hash_entry_size;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -2692,7 +2981,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       verdefs = asvinfo.verdefs;
 
       if (verdefs == NULL)
-       elf_link_remove_section_and_adjust_dynindices (info, s);
+       _bfd_strip_section_from_output (info, s);
       else
        {
          unsigned int cdefs;
@@ -2702,23 +2991,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          Elf_Internal_Verdef def;
          Elf_Internal_Verdaux defaux;
 
-         if (asvinfo.removed_dynamic)
-           {
-             /* Some dynamic symbols were changed to be local
-                symbols.  In this case, we renumber all of the
-                dynamic symbols, so that we don't have a hole.  If
-                the backend changed dynsymcount, then assume that the
-                new symbols are at the start.  This is the case on
-                the MIPS.  FIXME: The names of the removed symbols
-                will still be in the dynamic string table, wasting
-                space.  */
-             elf_hash_table (info)->dynsymcount =
-               1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount);
-             elf_link_hash_traverse (elf_hash_table (info),
-                                     elf_link_renumber_dynsyms,
-                                     (PTR) info);
-           }
-
          cdefs = 0;
          size = 0;
 
@@ -2758,7 +3030,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
          if (soname_indx != (bfd_size_type) -1)
            {
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) soname);
+             def.vd_hash = bfd_elf_hash (soname);
              defaux.vda_name = soname_indx;
            }
          else
@@ -2767,7 +3039,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              bfd_size_type indx;
 
              name = output_bfd->filename;
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) name);
+             def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
                                            name, true, false);
              if (indx == (bfd_size_type) -1)
@@ -2815,7 +3087,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                def.vd_flags |= VER_FLG_WEAK;
              def.vd_ndx = t->vernum + 1;
              def.vd_cnt = cdeps + 1;
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name);
+             def.vd_hash = bfd_elf_hash (t->name);
              def.vd_aux = sizeof (Elf_External_Verdef);
              if (t->next != NULL)
                def.vd_next = (sizeof (Elf_External_Verdef)
@@ -2885,7 +3157,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                                (PTR) &sinfo);
 
        if (elf_tdata (output_bfd)->verref == NULL)
-         elf_link_remove_section_and_adjust_dynindices (info, s);
+         _bfd_strip_section_from_output (info, s);
        else
          {
            Elf_Internal_Verneed *t;
@@ -2951,8 +3223,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
                for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
                  {
-                   a->vna_hash = bfd_elf_hash ((const unsigned char *)
-                                               a->vna_nodename);
+                   a->vna_hash = bfd_elf_hash (a->vna_nodename);
                    indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
                                               a->vna_nodename, true, false);
                    if (indx == (bfd_size_type) -1)
@@ -2977,7 +3248,12 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          }
       }
 
-      dynsymcount = elf_hash_table (info)->dynsymcount;
+      /* 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.  */
+
+      dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
 
       /* Work out the size of the symbol version section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version");
@@ -2985,10 +3261,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (dynsymcount == 0
          || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
        {
-         elf_link_remove_section_and_adjust_dynindices (info, s);
+         _bfd_strip_section_from_output (info, s);
          /* The DYNSYMCOUNT might have changed if we were going to
             output a dynamic symbol table entry for S.  */
-         dynsymcount = elf_hash_table (info)->dynsymcount;
+         dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
        }
       else
        {
@@ -3030,14 +3306,16 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       s = bfd_get_section_by_name (dynobj, ".hash");
       BFD_ASSERT (s != NULL);
-      s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8);
+      hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
+      s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
       s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
       if (s->contents == NULL)
        return false;
       memset (s->contents, 0, (size_t) s->_raw_size);
 
-      put_word (output_bfd, bucketcount, s->contents);
-      put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8));
+      bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
+      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, 
+              s->contents + hash_entry_size);
 
       elf_hash_table (info)->bucketcount = bucketcount;
 
@@ -3140,6 +3418,33 @@ elf_fix_symbol_flags (h, eif)
       h->plt.offset = (bfd_vma) -1;
     }
 
+  /* If this is a weak defined symbol in a dynamic object, and we know
+     the real definition in the dynamic object, copy interesting flags
+     over to the real definition.  */
+  if (h->weakdef != NULL)
+    {
+      struct elf_link_hash_entry *weakdef;
+
+      BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak);
+      weakdef = h->weakdef;
+      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
+                 || weakdef->root.type == bfd_link_hash_defweak);
+      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+
+      /* If the real definition is defined by a regular object file,
+        don't do anything special.  See the longer description in
+        elf_adjust_dynamic_symbol, below.  */
+      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->weakdef = NULL;
+      else
+       weakdef->elf_link_hash_flags |=
+         (h->elf_link_hash_flags
+          & (ELF_LINK_HASH_REF_REGULAR
+             | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+             | ELF_LINK_NON_GOT_REF));
+    }
+
   return true;
 }
 
@@ -3222,32 +3527,14 @@ elf_adjust_dynamic_symbol (h, data)
 
   if (h->weakdef != NULL)
     {
-      struct elf_link_hash_entry *weakdef;
+      /* If we get to this point, we know there is an implicit
+        reference by a regular object file via the weak symbol H.
+        FIXME: Is this really true?  What if the traversal finds
+        H->WEAKDEF before it finds H?  */
+      h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
 
-      BFD_ASSERT (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak);
-      weakdef = h->weakdef;
-      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
-                 || weakdef->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
-      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
-       {
-         /* This symbol is defined by a regular object file, so we
-            will not do anything special.  Clear weakdef for the
-            convenience of the processor backend.  */
-         h->weakdef = NULL;
-       }
-      else
-       {
-         /* There is an implicit reference by a regular object file
-            via the weak symbol.  */
-         weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
-         if (h->weakdef->elf_link_hash_flags
-             & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
-           weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
-         if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif))
-           return false;
-       }
+      if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif))
+       return false;
     }
 
   /* If a symbol has no type and no size and does not require a PLT
@@ -3470,7 +3757,6 @@ elf_link_assign_sym_version (h, data)
                              && info->shared
                              && ! sinfo->export_dynamic)
                            {
-                             sinfo->removed_dynamic = true;
                              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
                              h->elf_link_hash_flags &=~
                                ELF_LINK_HASH_NEEDS_PLT;
@@ -3586,7 +3872,6 @@ elf_link_assign_sym_version (h, data)
                          && info->shared
                          && ! sinfo->export_dynamic)
                        {
-                         sinfo->removed_dynamic = true;
                          h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
                          h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
                          h->dynindx = -1;
@@ -3611,7 +3896,6 @@ elf_link_assign_sym_version (h, data)
              && info->shared
              && ! sinfo->export_dynamic)
            {
-             sinfo->removed_dynamic = true;
              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
              h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
              h->dynindx = -1;
@@ -3624,26 +3908,6 @@ elf_link_assign_sym_version (h, data)
 
   return true;
 }
-
-/* This function is used to renumber the dynamic symbols, if some of
-   them are removed because they are marked as local.  This is called
-   via elf_link_hash_traverse.  */
-
-static boolean
-elf_link_renumber_dynsyms (h, data)
-     struct elf_link_hash_entry *h;
-     PTR data;
-{
-  struct bfd_link_info *info = (struct bfd_link_info *) data;
-
-  if (h->dynindx != -1)
-    {
-      h->dynindx = elf_hash_table (info)->dynsymcount;
-      ++elf_hash_table (info)->dynsymcount;
-    }
-
-  return true;
-}
 \f
 /* Final phase of ELF linker.  */
 
@@ -3721,38 +3985,91 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
      asection *o;
 {
   register struct elf_link_hash_entry **p, **pend;
+  unsigned reloc_count;
 
-  /* We are overestimating the size required for the relocation
-     sections, in the case that we are using both REL and RELA
-     relocations for a single section.  In that case, RELOC_COUNT will
-     be the total number of relocations required, and we allocate
-     space for that many REL relocations as well as that many RELA
-     relocations.  This approximation is wasteful of disk space.
-     However, until we keep track of how many of each kind of
-     relocation is required, it's difficult to calculate the right
-     value.  */
-  rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
+  /* Figure out how many relocations there will be.  */
+  if (rel_hdr == &elf_section_data (o)->rel_hdr)
+    reloc_count = elf_section_data (o)->rel_count;
+  else
+    reloc_count = elf_section_data (o)->rel_count2;
+
+  /* That allows us to calculate the size of the section.  */
+  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);
   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)
+    {
+      p = ((struct elf_link_hash_entry **)
+          bfd_malloc (o->reloc_count
+                      * sizeof (struct elf_link_hash_entry *)));
+      if (p == NULL && o->reloc_count != 0)
+       return false;
 
-  p = ((struct elf_link_hash_entry **)
-       bfd_malloc (o->reloc_count
-                  * sizeof (struct elf_link_hash_entry *)));
-  if (p == NULL && o->reloc_count != 0)
-    return false;
-
-  elf_section_data (o)->rel_hashes = p;
-  pend = p + o->reloc_count;
-  for (; p < pend; p++)
-    *p = NULL;
+      elf_section_data (o)->rel_hashes = p;
+      pend = p + o->reloc_count;
+      for (; p < pend; p++)
+       *p = NULL;
+    }
 
   return true;
 }
 
+/* When performing a relocateable link, the input relocations are
+   preserved.  But, if they reference global symbols, the indices
+   referenced must be updated.  Update all the relocations in
+   REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     unsigned int count;
+     struct elf_link_hash_entry **rel_hash;
+{
+  unsigned int i;
+
+  for (i = 0; i < count; i++, rel_hash++)
+    {
+      if (*rel_hash == NULL)
+       continue;
+
+      BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+      if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+       {
+         Elf_External_Rel *erel;
+         Elf_Internal_Rel irel;
+         
+         erel = (Elf_External_Rel *) rel_hdr->contents + i;
+         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);
+       }
+      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);
+         irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                    ELF_R_TYPE (irela.r_info));
+         elf_swap_reloca_out (abfd, &irela, erela);
+       }
+    }
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -3908,6 +4225,54 @@ elf_bfd_final_link (abfd, info)
   if (! _bfd_elf_compute_section_file_positions (abfd, info))
     goto error_return;
 
+  /* Figure out how many relocations we will have in each section.
+     Just using RELOC_COUNT isn't good enough since that doesn't
+     maintain a separate value for REL vs. RELA relocations.  */
+  if (info->relocateable)
+    for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+      for (o = sub->sections; o != NULL; o = o->next)
+       {
+         asection *output_section;
+
+         if (! o->linker_mark)
+           {
+             /* This section was omitted from the link.  */
+             continue;
+           }
+
+         output_section = o->output_section;
+
+         if (output_section != NULL
+             && (o->flags & SEC_RELOC) != 0)
+           {
+             struct bfd_elf_section_data *esdi 
+               = elf_section_data (o);
+             struct bfd_elf_section_data *esdo 
+               = elf_section_data (output_section);
+             unsigned int *rel_count;
+             unsigned int *rel_count2;
+
+             /* We must be careful to add the relocation froms the
+                input section to the right output count.  */
+             if (esdi->rel_hdr.sh_entsize == esdo->rel_hdr.sh_entsize)
+               {
+                 rel_count = &esdo->rel_count;
+                 rel_count2 = &esdo->rel_count2;
+               }
+             else
+               {
+                 rel_count = &esdo->rel_count2;
+                 rel_count2 = &esdo->rel_count;
+               }
+             
+             *rel_count += (esdi->rel_hdr.sh_size 
+                            / esdi->rel_hdr.sh_entsize);
+             if (esdi->rel_hdr2)
+               *rel_count2 += (esdi->rel_hdr2->sh_size 
+                               / esdi->rel_hdr2->sh_entsize);
+           }
+       }
+
   /* That created the reloc sections.  Set their sizes, and assign
      them file positions, and allocate some buffers.  */
   for (o = abfd->sections; o != NULL; o = o->next)
@@ -3925,6 +4290,11 @@ elf_bfd_final_link (abfd, info)
                                               o))
            goto error_return;
        }
+
+      /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
+        to count upwards while actually outputting the relocations. */
+      elf_section_data (o)->rel_count = 0;
+      elf_section_data (o)->rel_count2 = 0;
     }
 
   _bfd_elf_assign_file_positions_for_relocs (abfd);
@@ -4026,7 +4396,8 @@ elf_bfd_final_link (abfd, info)
   finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
   finfo.internal_relocs = ((Elf_Internal_Rela *)
                           bfd_malloc (max_internal_reloc_count
-                                      * sizeof (Elf_Internal_Rela)));
+                                      * sizeof (Elf_Internal_Rela)
+                                      * bed->s->int_rels_per_ext_rel));
   finfo.external_syms = ((Elf_External_Sym *)
                         bfd_malloc (max_sym_count
                                     * sizeof (Elf_External_Sym)));
@@ -4117,11 +4488,79 @@ elf_bfd_final_link (abfd, info)
        return false;
     }
 
-  /* The sh_info field records the index of the first non local
-     symbol.  */
+  /* The sh_info field records the index of the first non local symbol.  */
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
   if (dynamic)
-    elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
+    {
+      Elf_Internal_Sym sym;
+      Elf_External_Sym *dynsym =
+       (Elf_External_Sym *)finfo.dynsym_sec->contents;
+      long last_local = 0;
+
+      /* Write out the section symbols for the output sections.  */
+      if (info->shared)
+       {
+         asection *s;
+
+         sym.st_size = 0;
+         sym.st_name = 0;
+         sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+         sym.st_other = 0;
+
+         for (s = abfd->sections; s != NULL; s = s->next)
+           {
+             int indx;
+             indx = elf_section_data (s)->this_idx;
+             BFD_ASSERT (indx > 0);
+             sym.st_shndx = indx;
+             sym.st_value = s->vma;
+
+             elf_swap_symbol_out (abfd, &sym,
+                                  dynsym + elf_section_data (s)->dynindx);
+           }
+
+         last_local = bfd_count_sections (abfd);
+       }
+
+      /* Write out the local dynsyms.  */
+      if (elf_hash_table (info)->dynlocal)
+       {
+         struct elf_link_local_dynamic_entry *e;
+         for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+           {
+             asection *s;
+
+             sym.st_size = e->isym.st_size;
+             sym.st_other = e->isym.st_other;
+
+             /* Copy the internal symbol as is.
+                Note that we saved a word of storage and overwrote
+                 the original st_name with the dynstr_index.  */
+              sym = e->isym;
+
+             if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE)
+               {
+                 s = bfd_section_from_elf_index (e->input_bfd,
+                                                 e->isym.st_shndx);
+
+                 sym.st_shndx =
+                   elf_section_data (s->output_section)->this_idx;
+                 sym.st_value = (s->output_section->vma
+                                 + s->output_offset
+                                 + e->isym.st_value);
+               }
+
+             if (last_local < e->dynindx)
+               last_local = e->dynindx;
+
+             elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+           }
+       }
+
+      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+       last_local + 1;
+    }
 
   /* We get the global symbols from the hash table.  */
   eoinfo.failed = false;
@@ -4132,6 +4571,18 @@ elf_bfd_final_link (abfd, info)
   if (eoinfo.failed)
     return false;
 
+  /* If backend needs to output some symbols not present in the hash
+     table, do it now.  */
+  if (bed->elf_backend_output_arch_syms)
+    {
+      if (! (*bed->elf_backend_output_arch_syms)
+             (abfd, info, (PTR) &finfo,
+              (boolean (*) PARAMS ((PTR, const char *,
+                           Elf_Internal_Sym *, asection *)))
+              elf_link_output_sym))
+       return false;
+    }      
+
   /* Flush all symbols to the file.  */
   if (! elf_link_flush_output_syms (&finfo))
     return false;
@@ -4166,48 +4617,17 @@ elf_bfd_final_link (abfd, info)
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      struct elf_link_hash_entry **rel_hash;
-      Elf_Internal_Shdr *rel_hdr;
-
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      rel_hash = elf_section_data (o)->rel_hashes;
-      rel_hdr = &elf_section_data (o)->rel_hdr;
-      BFD_ASSERT (elf_section_data (o)->rel_count == o->reloc_count);
-      for (i = 0; i < o->reloc_count; i++, rel_hash++)
-       {
-         if (*rel_hash == NULL)
-           continue;
-
-         BFD_ASSERT ((*rel_hash)->indx >= 0);
-
-         if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-           {
-             Elf_External_Rel *erel;
-             Elf_Internal_Rel irel;
-
-             erel = (Elf_External_Rel *) rel_hdr->contents + i;
-             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);
-           }
-         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);
-             irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                        ELF_R_TYPE (irela.r_info));
-             elf_swap_reloca_out (abfd, &irela, erela);
-           }
-       }
+      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_count));
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -4704,14 +5124,23 @@ elf_link_output_extsym (h, data)
 
   /* If we are marking the symbol as undefined, and there are no
      non-weak references to this symbol from a regular object, then
-     mark the symbol as weak undefined.  We can't do this earlier,
+     mark the symbol as weak undefined; if there are non-weak
+     references, mark the symbol as strong.  We can't do this earlier,
      because it might not be marked as undefined until the
      finish_dynamic_symbol routine gets through with it.  */
   if (sym.st_shndx == SHN_UNDEF
-      && sym.st_info == ELF_ST_INFO (STB_GLOBAL, h->type)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
-      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) == 0)
-    sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
+      && (ELF_ST_BIND(sym.st_info) == STB_GLOBAL
+         || ELF_ST_BIND(sym.st_info) == STB_WEAK))
+    {
+      int bindtype;
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0)
+       bindtype = STB_GLOBAL;
+      else
+       bindtype = STB_WEAK;
+      sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
+    }
 
   /* 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
@@ -4721,6 +5150,7 @@ elf_link_output_extsym (h, data)
     {
       size_t bucketcount;
       size_t bucket;
+      size_t hash_entry_size;
       bfd_byte *bucketpos;
       bfd_vma chain;
 
@@ -4733,13 +5163,15 @@ elf_link_output_extsym (h, data)
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
+      hash_entry_size 
+       = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
       bucketpos = ((bfd_byte *) finfo->hash_sec->contents
-                  + (bucket + 2) * (ARCH_SIZE / 8));
-      chain = get_word (finfo->output_bfd, bucketpos);
-      put_word (finfo->output_bfd, h->dynindx, bucketpos);
-      put_word (finfo->output_bfd, chain,
-               ((bfd_byte *) finfo->hash_sec->contents
-                + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8)));
+                  + (bucket + 2) * hash_entry_size);
+      chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
+      bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
+      bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
+              ((bfd_byte *) finfo->hash_sec->contents
+               + (bucketcount + 2 + h->dynindx) * hash_entry_size));
 
       if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
        {
@@ -4802,7 +5234,7 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
   Elf_Internal_Rela *irelaend;
   Elf_Internal_Shdr *output_rel_hdr;
   asection *output_section;
-  unsigned int *rel_countp;
+  unsigned int *rel_countp = NULL;
 
   output_section = input_section->output_section;
   output_rel_hdr = NULL;
@@ -4881,10 +5313,11 @@ elf_link_input_bfd (finfo, input_bfd)
   long *pindex;
   asection **ppsection;
   asection *o;
+  struct elf_backend_data *bed;
 
   output_bfd = finfo->output_bfd;
-  relocate_section =
-    get_elf_backend_data (output_bfd)->elf_backend_relocate_section;
+  bed = get_elf_backend_data (output_bfd);
+  relocate_section = bed->elf_backend_relocate_section;
 
   /* If this is a dynamic object, we don't want to do anything here:
      we don't want the local symbols, and we don't want the section
@@ -5121,9 +5554,11 @@ elf_link_input_bfd (finfo, input_bfd)
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
-             irelaend = irela + o->reloc_count;
+             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);
+                         + elf_section_data (o->output_section)->rel_count
+                         + elf_section_data (o->output_section)->rel_count2);
              for (; irela < irelaend; irela++, rel_hash++)
                {
                  unsigned long r_symndx;
@@ -5313,7 +5748,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
 
   /* Figure out the symbol index.  */
   rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
-                 + elf_section_data (output_section)->rel_count);
+                 + elf_section_data (output_section)->rel_count
+                 + elf_section_data (output_section)->rel_count2);
   if (link_order->type == bfd_section_reloc_link_order)
     {
       indx = link_order->u.reloc.p->u.section->target_index;
@@ -5731,6 +6167,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
       size_t extsymoff;
       Elf_External_Sym *locsyms, *freesyms = NULL;
       bfd *input_bfd = sec->owner;
+      struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
 
       /* GCFIXME: how to arrange so that relocs and symbols are not
         reread continually?  */
@@ -5774,7 +6211,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
          ret = false;
          goto out1;
        }
-      relend = relstart + sec->reloc_count;
+      relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
       for (rel = relstart; rel < relend; rel++)
        {
@@ -5980,6 +6417,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
   asection *sec;
   bfd_vma hstart, hend;
   Elf_Internal_Rela *relstart, *relend, *rel;
+  struct elf_backend_data *bed;
 
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
@@ -5997,7 +6435,8 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
              (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
   if (!relstart)
     return *(boolean *)okp = false;
-  relend = relstart + sec->reloc_count;
+  bed = get_elf_backend_data (sec->owner);
+  relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
   for (rel = relstart; rel < relend; ++rel)
     if (rel->r_offset >= hstart && rel->r_offset < hend)
@@ -6131,8 +6570,8 @@ win:
 
 boolean
 elf_gc_record_vtentry (abfd, sec, h, addend)
-     bfd *abfd;
-     asection *sec;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *h;
      bfd_vma addend;
 {
@@ -6158,30 +6597,31 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
 
       /* Allocate one extra entry for use as a "done" flag for the
         consolidation pass.  */
-      bytes = (size / FILE_ALIGN + 1) * sizeof(boolean);
+      bytes = (size / FILE_ALIGN + 1) * sizeof (boolean);
 
       if (ptr)
        {
-         size_t oldbytes;
-
-         ptr = realloc (ptr-1, bytes);
-         if (ptr == NULL)
-           return false;
+         ptr = bfd_realloc (ptr - 1, bytes);
+         
+         if (ptr != NULL)
+           {
+             size_t oldbytes;
 
-         oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof(boolean);
-         memset (ptr + oldbytes, 0, bytes - oldbytes);
+             oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean);
+             memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+           }
        }
       else
-       {
-         ptr = calloc (1, bytes);
-         if (ptr == NULL)
-           return false;
-       }
+       ptr = bfd_zmalloc (bytes);
 
+      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_used = ptr + 1;
       h->vtable_entries_size = size;
     }
+  
   h->vtable_entries_used[addend / FILE_ALIGN] = true;
 
   return true;
This page took 0.042414 seconds and 4 git commands to generate.