* Makefile.am: Run "make dep-am".
[deliverable/binutils-gdb.git] / bfd / elfcode.h
index 892ae7a332aeaf20dfdce83305ab784344bdc630..203323cdb5e66d36ed774b136798a62bfedb0b2a 100644 (file)
@@ -203,9 +203,10 @@ static char *elf_symbol_flags PARAMS ((flagword));
    format.  */
 
 void
-elf_swap_symbol_in (abfd, src, dst)
+elf_swap_symbol_in (abfd, src, shndx, dst)
      bfd *abfd;
      const Elf_External_Sym *src;
+     const Elf_External_Sym_Shndx *shndx;
      Elf_Internal_Sym *dst;
 {
   int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
@@ -219,24 +220,40 @@ elf_swap_symbol_in (abfd, src, dst)
   dst->st_info = H_GET_8 (abfd, src->st_info);
   dst->st_other = H_GET_8 (abfd, src->st_other);
   dst->st_shndx = H_GET_16 (abfd, src->st_shndx);
+  if (dst->st_shndx == SHN_XINDEX)
+    {
+      if (shndx == NULL)
+       abort ();
+      dst->st_shndx = H_GET_32 (abfd, shndx->est_shndx);
+    }
 }
 
 /* Translate an ELF symbol in internal format into an ELF symbol in external
    format.  */
 
 void
-elf_swap_symbol_out (abfd, src, cdst)
+elf_swap_symbol_out (abfd, src, cdst, shndx)
      bfd *abfd;
      const Elf_Internal_Sym *src;
      PTR cdst;
+     PTR shndx;
 {
+  unsigned int tmp;
   Elf_External_Sym *dst = (Elf_External_Sym *) cdst;
   H_PUT_32 (abfd, src->st_name, dst->st_name);
   H_PUT_WORD (abfd, src->st_value, dst->st_value);
   H_PUT_WORD (abfd, src->st_size, dst->st_size);
   H_PUT_8 (abfd, src->st_info, dst->st_info);
   H_PUT_8 (abfd, src->st_other, dst->st_other);
-  H_PUT_16 (abfd, src->st_shndx, dst->st_shndx);
+  tmp = src->st_shndx;
+  if (tmp > SHN_HIRESERVE)
+    {
+      if (shndx == NULL)
+       abort ();
+      H_PUT_32 (abfd, tmp, shndx);
+      tmp = SHN_XINDEX;
+    }
+  H_PUT_16 (abfd, tmp, dst->st_shndx);
 }
 
 /* Translate an ELF file header in external format into an ELF file header in
@@ -486,6 +503,16 @@ elf_file_p (x_ehdrp)
          && (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3));
 }
 
+struct bfd_preserve
+{
+  const struct bfd_arch_info *arch_info;
+  struct elf_obj_tdata *tdata;
+  struct bfd_hash_table section_htab;
+  struct sec *sections;
+  struct sec **section_tail;
+  unsigned int section_count;
+};
+
 /* Check to see if the file associated with ABFD matches the target vector
    that ABFD points to.
 
@@ -502,23 +529,16 @@ elf_object_p (abfd)
   Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
   Elf_External_Shdr x_shdr;    /* Section header table entry, external form */
   Elf_Internal_Shdr i_shdr;
-  Elf_Internal_Shdr *i_shdrp = NULL; /* Section header table, internal form */
+  Elf_Internal_Shdr *i_shdrp /* Section header table, internal form */
   unsigned int shindex;
   char *shstrtab;              /* Internal copy of section header stringtab */
   struct elf_backend_data *ebd;
-  struct elf_obj_tdata *preserved_tdata = elf_tdata (abfd);
-  struct sec *preserved_sections = abfd->sections;
-  unsigned int preserved_section_count = abfd->section_count;
-  enum bfd_architecture previous_arch = bfd_get_arch (abfd);
-  unsigned long previous_mach = bfd_get_mach (abfd);
+  struct bfd_preserve preserve;
   struct elf_obj_tdata *new_tdata = NULL;
   asection *s;
   bfd_size_type amt;
 
-  /* Clear section information, since there might be a recognized bfd that
-     we now check if we can replace, and we don't want to append to it.  */
-  abfd->sections = NULL;
-  abfd->section_count = 0;
+  preserve.arch_info = abfd->arch_info;
 
   /* Read in the ELF header in external format.  */
 
@@ -565,8 +585,21 @@ elf_object_p (abfd)
   new_tdata = (struct elf_obj_tdata *) bfd_zalloc (abfd, amt);
   if (new_tdata == NULL)
     goto got_no_match;
+  preserve.tdata = elf_tdata (abfd);
   elf_tdata (abfd) = new_tdata;
 
+  /* Clear section information, since there might be a recognized bfd that
+     we now check if we can replace, and we don't want to append to it.  */
+  preserve.sections = abfd->sections;
+  preserve.section_tail = abfd->section_tail;
+  preserve.section_count = abfd->section_count;
+  preserve.section_htab = abfd->section_htab;
+  abfd->sections = NULL;
+  abfd->section_tail = &abfd->sections;
+  abfd->section_count = 0;
+  if (!bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc))
+    goto got_no_match;
+
   /* Now that we know the byte order, swap in the rest of the header */
   i_ehdrp = elf_elfheader (abfd);
   elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp);
@@ -667,14 +700,17 @@ elf_object_p (abfd)
   if (i_ehdrp->e_shnum != 0)
     {
       Elf_Internal_Shdr *shdrp;
+      unsigned int num_sec;
 
       amt = sizeof (*i_shdrp) * i_ehdrp->e_shnum;
       i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
       if (!i_shdrp)
        goto got_no_match;
-      amt = sizeof (i_shdrp) * i_ehdrp->e_shnum;
-      if (i_ehdrp->e_shnum > SHN_LORESERVE)
-       amt += sizeof (i_shdrp) * (SHN_HIRESERVE + 1 - SHN_LORESERVE);
+      num_sec = i_ehdrp->e_shnum;
+      if (num_sec > SHN_LORESERVE)
+       num_sec += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+      elf_numsections (abfd) = num_sec;
+      amt = sizeof (i_shdrp) * num_sec;
       elf_elfsections (abfd) = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt);
       if (!elf_elfsections (abfd))
        goto got_no_match;
@@ -682,36 +718,37 @@ elf_object_p (abfd)
       memcpy (i_shdrp, &i_shdr, sizeof (*i_shdrp));
       shdrp = i_shdrp;
       shindex = 0;
-      if (i_ehdrp->e_shnum > SHN_LORESERVE)
+      if (num_sec > SHN_LORESERVE)
        {
          for ( ; shindex < SHN_LORESERVE; shindex++)
            elf_elfsections (abfd)[shindex] = shdrp++;
          for ( ; shindex < SHN_HIRESERVE + 1; shindex++)
-           elf_elfsections (abfd)[shindex] = NULL;
+           elf_elfsections (abfd)[shindex] = i_shdrp;
        }
-      for ( ; shindex < i_ehdrp->e_shnum; shindex++)
+      for ( ; shindex < num_sec; shindex++)
        elf_elfsections (abfd)[shindex] = shdrp++;
-    }
 
-  /* Read in the rest of the section header table and convert it to
-     internal form.  */
-  for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++)
-    {
-      if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd)
-         != sizeof (x_shdr))
-       goto got_no_match;
-      elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex);
-
-      /* If the section is loaded, but not page aligned, clear
-         D_PAGED.  */
-      if (i_shdrp[shindex].sh_size != 0
-         && (i_shdrp[shindex].sh_flags & SHF_ALLOC) != 0
-         && i_shdrp[shindex].sh_type != SHT_NOBITS
-         && (((i_shdrp[shindex].sh_addr - i_shdrp[shindex].sh_offset)
-              % ebd->maxpagesize)
-             != 0))
-       abfd->flags &= ~D_PAGED;
+      /* Read in the rest of the section header table and convert it
+        to internal form.  */
+      for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++)
+       {
+         if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd)
+             != sizeof (x_shdr))
+           goto got_no_match;
+         elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex);
+
+         /* If the section is loaded, but not page aligned, clear
+            D_PAGED.  */
+         if (i_shdrp[shindex].sh_size != 0
+             && (i_shdrp[shindex].sh_flags & SHF_ALLOC) != 0
+             && i_shdrp[shindex].sh_type != SHT_NOBITS
+             && (((i_shdrp[shindex].sh_addr - i_shdrp[shindex].sh_offset)
+                  % ebd->maxpagesize)
+                 != 0))
+           abfd->flags &= ~D_PAGED;
+       }
     }
+
   if (i_ehdrp->e_shstrndx)
     {
       if (! bfd_section_from_shdr (abfd, i_ehdrp->e_shstrndx))
@@ -752,6 +789,8 @@ elf_object_p (abfd)
 
   if (i_ehdrp->e_shstrndx != 0)
     {
+      unsigned int num_sec;
+
       shstrtab = bfd_elf_get_str_section (abfd, i_ehdrp->e_shstrndx);
       if (!shstrtab)
        goto got_no_match;
@@ -759,11 +798,13 @@ elf_object_p (abfd)
       /* Once all of the section headers have been read and converted, we
         can start processing them.  Note that the first section header is
         a dummy placeholder entry, so we ignore it.  */
-
-      for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++)
+      num_sec = elf_numsections (abfd);
+      for (shindex = 1; shindex < num_sec; shindex++)
        {
          if (! bfd_section_from_shdr (abfd, shindex))
            goto got_no_match;
+         if (shindex == SHN_LORESERVE - 1)
+           shindex += SHN_HIRESERVE + 1 - SHN_LORESERVE;
        }
     }
 
@@ -794,6 +835,10 @@ elf_object_p (abfd)
        }
     }
 
+  /* It would be nice to be able to free more memory here, eg. old
+     elf_elfsections, old tdata, but that's not possible since these
+     blocks are sitting inside obj_alloc'd memory.  */
+  bfd_hash_table_free (&preserve.section_htab);
   return (abfd->xvec);
 
  got_wrong_format_error:
@@ -806,20 +851,22 @@ elf_object_p (abfd)
      target-specific elf_backend_object_p function.  Note that saving the
      whole bfd here and restoring it would be even worse; the first thing
      you notice is that the cached bfd file position gets out of sync.  */
-  bfd_default_set_arch_mach (abfd, previous_arch, previous_mach);
   bfd_set_error (bfd_error_wrong_format);
+
  got_no_match:
-  if (new_tdata != NULL
-      && new_tdata->elf_sect_ptr != NULL)
-    bfd_release (abfd, new_tdata->elf_sect_ptr);
-  if (i_shdrp != NULL)
-    bfd_release (abfd, i_shdrp);
+  abfd->arch_info = preserve.arch_info;
   if (new_tdata != NULL)
-    bfd_release (abfd, new_tdata);
-  elf_tdata (abfd) = preserved_tdata;
-  abfd->sections = preserved_sections;
-  abfd->section_count = preserved_section_count;
-  return (NULL);
+    {
+      /* bfd_release frees all memory more recently bfd_alloc'd than
+        its arg, as well as its arg.  */
+      bfd_release (abfd, new_tdata);
+      elf_tdata (abfd) = preserve.tdata;
+      abfd->section_htab = preserve.section_htab;
+      abfd->sections = preserve.sections;
+      abfd->section_tail = preserve.section_tail;
+      abfd->section_count = preserve.section_count;
+    }
+  return NULL;
 }
 \f
 /* ELF .o/exec file writing */
@@ -1079,6 +1126,7 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
   elf_symbol_type *symbase;    /* Buffer for generated bfd symbols */
   Elf_Internal_Sym i_sym;
   Elf_External_Sym *x_symp = NULL;
+  Elf_External_Sym_Shndx *x_shndx = NULL;
   Elf_External_Versym *x_versymp = NULL;
   bfd_size_type amt;
 
@@ -1094,8 +1142,24 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
 
   if (! dynamic)
     {
+      Elf_Internal_Shdr *shndx_hdr;
+
       hdr = &elf_tdata (abfd)->symtab_hdr;
+      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
       verhdr = NULL;
+
+      /* If we have a SHT_SYMTAB_SHNDX section for the symbol table,
+        read the raw contents.  */
+      if (elf_elfsections (abfd) != NULL
+         && elf_elfsections (abfd)[shndx_hdr->sh_link] == hdr)
+       {
+         amt = shndx_hdr->sh_size;
+         x_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+         if (x_shndx == NULL
+             || bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+             || bfd_bread ((PTR) x_shndx, amt, abfd) != amt)
+           goto error_return;
+       }
     }
   else
     {
@@ -1115,7 +1179,7 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
     }
 
   if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
-    return -1;
+    goto error_return;
 
   symcount = hdr->sh_size / sizeof (Elf_External_Sym);
 
@@ -1126,20 +1190,20 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
       unsigned long i;
 
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
-       return -1;
+       goto error_return;
 
       amt = symcount;
       amt *= sizeof (elf_symbol_type);
       symbase = (elf_symbol_type *) bfd_zalloc (abfd, amt);
       if (symbase == (elf_symbol_type *) NULL)
-       return -1;
+       goto error_return;
       sym = symbase;
 
       /* Temporarily allocate room for the raw ELF symbols.  */
       amt = symcount;
       amt *= sizeof (Elf_External_Sym);
       x_symp = (Elf_External_Sym *) bfd_malloc (amt);
-      if (x_symp == NULL && symcount != 0)
+      if (x_symp == NULL)
        goto error_return;
 
       if (bfd_bread ((PTR) x_symp, amt, abfd) != amt)
@@ -1178,7 +1242,8 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
       /* Skip first symbol, which is a null dummy.  */
       for (i = 1; i < symcount; i++)
        {
-         elf_swap_symbol_in (abfd, x_symp + i, &i_sym);
+         elf_swap_symbol_in (abfd, x_symp + i,
+                             x_shndx + (x_shndx != NULL ? i : 0), &i_sym);
          memcpy (&sym->internal_elf_sym, &i_sym, sizeof (Elf_Internal_Sym));
 #ifdef ELF_KEEP_EXTSYM
          memcpy (&sym->native_elf_sym, x_symp + i, sizeof (Elf_External_Sym));
@@ -1191,7 +1256,12 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
 
          sym->symbol.value = i_sym.st_value;
 
-         if (i_sym.st_shndx > 0 && i_sym.st_shndx < SHN_LORESERVE)
+         if (i_sym.st_shndx == SHN_UNDEF)
+           {
+             sym->symbol.section = bfd_und_section_ptr;
+           }
+         else if (i_sym.st_shndx < SHN_LORESERVE
+                  || i_sym.st_shndx > SHN_HIRESERVE)
            {
              sym->symbol.section = section_from_elf_index (abfd,
                                                            i_sym.st_shndx);
@@ -1216,10 +1286,6 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
                 moment) about the alignment.  */
              sym->symbol.value = i_sym.st_size;
            }
-         else if (i_sym.st_shndx == SHN_UNDEF)
-           {
-             sym->symbol.section = bfd_und_section_ptr;
-           }
          else
            sym->symbol.section = bfd_abs_section_ptr;
 
@@ -1306,12 +1372,17 @@ elf_slurp_symbol_table (abfd, symptrs, dynamic)
       *symptrs = 0;            /* Final null pointer */
     }
 
+  if (x_shndx != NULL)
+    free (x_shndx);
   if (x_versymp != NULL)
     free (x_versymp);
   if (x_symp != NULL)
     free (x_symp);
   return symcount;
+
 error_return:
+  if (x_shndx != NULL)
+    free (x_shndx);
   if (x_versymp != NULL)
     free (x_versymp);
   if (x_symp != NULL)
This page took 0.038025 seconds and 4 git commands to generate.