* elf64-sparc.c (sparc64_elf_relocate_section): Adjust addend of
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 079917ef75d5288c0c2925cd2c03b2b618eb3b28..c116ed5d44aa9de8beac05223cdf4760ff83bb3c 100644 (file)
@@ -4494,6 +4494,8 @@ struct elf_final_link_info
   size_t symbuf_count;
   /* Number of symbols which fit in symbuf.  */
   size_t symbuf_size;
+  /* And same for symshndxbuf.  */
+  size_t shndxbuf_size;
 };
 
 static boolean elf_link_output_sym
@@ -4669,8 +4671,9 @@ struct elf_link_sort_rela
   enum elf_reloc_type_class type;
   union
   {
-    Elf_Internal_Rel rel;
-    Elf_Internal_Rela rela;
+    /* We use these as arrays of size int_rels_per_ext_rel.  */
+    Elf_Internal_Rel rel[1];
+    Elf_Internal_Rela rela[1];
   } u;
 };
 
@@ -4690,13 +4693,13 @@ elf_link_sort_cmp1 (A, B)
     return 1;
   if (relativea > relativeb)
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) < ELF_R_SYM (b->u.rel->r_info))
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) > ELF_R_SYM (b->u.rel->r_info))
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4720,9 +4723,9 @@ elf_link_sort_cmp2 (A, B)
     return -1;
   if (copya > copyb)
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4740,6 +4743,7 @@ elf_link_sort_relocs (abfd, info, psec)
   size_t i, j, ret;
   struct elf_link_sort_rela *rela;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int i2e = bed->s->int_rels_per_ext_rel;
 
   reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
   if (reldyn == NULL || reldyn->_raw_size == 0)
@@ -4763,7 +4767,23 @@ elf_link_sort_relocs (abfd, info, psec)
   if (size != reldyn->_raw_size)
     return 0;
 
-  rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+  /* We waste some memory here when N = i2e is greater than 1, since
+     we allocate space for N * sizeof (*rela) where sizeof (*rela) +
+     (N - 1) * sizeof (Elf_Internal_Rel/Rela) would do.  Also, we use
+     rela[k] only when k is a multiple of N, and then we index the
+     array within the union, such that rela[k].u.rel[i], i < N, is the
+     (i+1)th internal relocation corresponding to the (k/N)th external
+     relocation.  This is done such that the relocation swap-in and
+     swap-out functions can gen pointers to arrays of internal
+     relocations that form a single external relocation.
+
+     If C permitted arrays of structures with dynamic sizes, we could
+     do better, but trying to avoid wasting space at the end of the
+     chunk from rela[k] to rela[k+N-1] would require us to allocate a
+     separate array of pointers and since most ports have N == 1, this
+     would be more wasteful.  */
+  rela = (struct elf_link_sort_rela *) bfd_zmalloc
+    (sizeof (*rela) * count * i2e);
   if (rela == NULL)
     {
       (*info->callbacks->warning)
@@ -4784,15 +4804,16 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_in)
-                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel,
+                                           s->u.rel);
                else
-                 elf_swap_reloc_in (abfd, erel, &s->u.rel);
+                 elf_swap_reloc_in (abfd, erel, s->u.rel);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
        else
@@ -4802,30 +4823,34 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_in)
                  (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
-                                            &s->u.rela);
+                                            s->u.rela);
                else
-                 elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+                 elf_swap_reloca_in (dynobj, erela, s->u.rela);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
       }
 
-  qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
-  for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+  qsort (rela, (size_t) count, sizeof (*rela) * i2e, elf_link_sort_cmp1);
+  for (ret = 0; ret < count * i2e && rela[ret].type == reloc_class_relative;
+       ret += i2e)
     ;
-  for (i = ret, j = ret; i < count; i++)
+  for (i = ret, j = ret; i < count * i2e; i += i2e)
     {
-      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+      if (ELF_R_SYM (rela[i].u.rel->r_info)
+         != ELF_R_SYM (rela[j].u.rel->r_info))
        j = i;
-      rela[i].offset = rela[j].u.rel.r_offset;
+      rela[i].offset = rela[j].u.rel->r_offset;
     }
-  qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+  ret /= i2e;
+  qsort (rela + ret, (size_t) count - ret,
+        sizeof (*rela) * i2e, elf_link_sort_cmp2);
 
   for (o = dynobj->sections; o != NULL; o = o->next)
     if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
@@ -4839,14 +4864,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_out)
-                 (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+                 (*bed->s->swap_reloc_out) (abfd, s->u.rel,
                                             (bfd_byte *) erel);
                else
-                 elf_swap_reloc_out (abfd, &s->u.rel, erel);
+                 elf_swap_reloc_out (abfd, s->u.rel, erel);
              }
          }
        else
@@ -4856,14 +4881,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_out)
-                 (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+                 (*bed->s->swap_reloca_out) (dynobj, s->u.rela,
                                              (bfd_byte *) erela);
                else
-                 elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+                 elf_swap_reloca_out (dynobj, s->u.rela, erela);
              }
          }
       }
@@ -4896,6 +4921,7 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Sym elfsym;
   unsigned int i;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
@@ -4949,6 +4975,7 @@ elf_bfd_final_link (abfd, info)
   finfo.symbuf = NULL;
   finfo.symshndxbuf = NULL;
   finfo.symbuf_count = 0;
+  finfo.shndxbuf_size = 0;
   finfo.first_tls_sec = NULL;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     if ((o->flags & SEC_THREAD_LOCAL) != 0
@@ -5169,9 +5196,7 @@ elf_bfd_final_link (abfd, info)
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
   symtab_hdr->sh_type = SHT_SYMTAB;
-  symtab_hdr->sh_flags = 0;
-  symtab_hdr->sh_addr = 0;
-  symtab_hdr->sh_size = 0;
+  /* sh_flags, sh_addr and sh_size all start off zero.  */
   symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
@@ -5198,9 +5223,11 @@ elf_bfd_final_link (abfd, info)
     goto error_return;
   if (elf_numsections (abfd) > SHN_LORESERVE)
     {
-      amt = finfo.symbuf_size;
+      /* Wild guess at number of output symbols.  realloc'd as needed.  */
+      amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
+      finfo.shndxbuf_size = amt;
       amt *= sizeof (Elf_External_Sym_Shndx);
-      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
       if (finfo.symshndxbuf == NULL)
        goto error_return;
     }
@@ -5260,7 +5287,7 @@ elf_bfd_final_link (abfd, info)
          if (! elf_link_output_sym (&finfo, (const char *) NULL,
                                     &elfsym, o))
            goto error_return;
-         if (i == SHN_LORESERVE)
+         if (i == SHN_LORESERVE - 1)
            i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
        }
     }
@@ -5535,6 +5562,24 @@ elf_bfd_final_link (abfd, info)
   /* Now we know the size of the symtab section.  */
   off += symtab_hdr->sh_size;
 
+  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (symtab_shndx_hdr->sh_name != 0)
+    {
+      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+      amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_size = amt;
+
+      off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
+                                                      off, true);
+
+      if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
+         || (bfd_bwrite ((PTR) finfo.symshndxbuf, amt, abfd) != amt))
+       return false;
+    }
+
+
   /* Finish up and write out the symbol string table (.strtab)
      section.  */
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
@@ -5843,7 +5888,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5877,7 +5922,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5936,11 +5981,24 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
   dest = finfo->symbuf + finfo->symbuf_count;
   destshndx = finfo->symshndxbuf;
   if (destshndx != NULL)
-    destshndx += finfo->symbuf_count;
-  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
-  ++finfo->symbuf_count;
+    {
+      if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
+       {
+         bfd_size_type amt;
 
-  ++ bfd_get_symcount (finfo->output_bfd);
+         amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
+         finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+         if (destshndx == NULL)
+           return false;
+         memset ((char *) destshndx + amt, 0, amt);
+         finfo->shndxbuf_size *= 2;
+       }
+      destshndx += bfd_get_symcount (finfo->output_bfd);
+    }
+
+  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
+  finfo->symbuf_count += 1;
+  bfd_get_symcount (finfo->output_bfd) += 1;
 
   return true;
 }
@@ -5965,20 +6023,6 @@ elf_link_flush_output_syms (finfo)
        return false;
 
       hdr->sh_size += amt;
-
-      if (finfo->symshndxbuf != NULL)
-       {
-         hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr;
-         pos = hdr->sh_offset + hdr->sh_size;
-         amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx);
-         if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
-             || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd)
-                 != amt))
-           return false;
-
-         hdr->sh_size += amt;
-       }
-
       finfo->symbuf_count = 0;
     }
 
This page took 0.027787 seconds and 4 git commands to generate.