* libelf.h (struct bfd_elf_section_data): Add relocs field.
authorIan Lance Taylor <ian@airs.com>
Sun, 17 Jul 1994 01:15:42 +0000 (01:15 +0000)
committerIan Lance Taylor <ian@airs.com>
Sun, 17 Jul 1994 01:15:42 +0000 (01:15 +0000)
(shdr_name): Remove; unused.
* elfcode.h (elf_slurp_reloc_table): Rewrote to handle both REL
and RELA relocs.  Free up the unswapped relocs.  Permit the relocs
to be cached in the section_data.  Correct the reloc address.
(elf_slurp_reloca_table): Remove.
(elf_canonicalize_reloc): Rewrote.
(elf_link_input_bfd): Permit the relocs to be cached in the
section data.

bfd/ChangeLog
bfd/elfcode.h
bfd/libelf.h

index 8146194..310c12d 100644 (file)
@@ -1,3 +1,15 @@
+Sat Jul 16 21:10:39 1994  Ian Lance Taylor  (ian@sanguine.cygnus.com)
+
+       * libelf.h (struct bfd_elf_section_data): Add relocs field.
+       (shdr_name): Remove; unused.
+       * elfcode.h (elf_slurp_reloc_table): Rewrote to handle both REL
+       and RELA relocs.  Free up the unswapped relocs.  Permit the relocs
+       to be cached in the section_data.  Correct the reloc address.
+       (elf_slurp_reloca_table): Remove.
+       (elf_canonicalize_reloc): Rewrote.
+       (elf_link_input_bfd): Permit the relocs to be cached in the
+       section data.
+
 Sat Jul 16 13:55:38 1994  Stan Shebs  (shebs@andros.cygnus.com)
 
        * config.bfd (m88*-harris-cxux*): Recognize.
index 756d08d..223b751 100644 (file)
@@ -145,6 +145,8 @@ static int elf_section_from_bfd_section PARAMS ((bfd *, struct sec *));
 
 static long elf_slurp_symbol_table PARAMS ((bfd *, asymbol **, boolean));
 
+static boolean elf_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **));
+
 static int elf_symbol_from_bfd_symbol PARAMS ((bfd *,
                                             struct symbol_cache_entry **));
 
@@ -2899,105 +2901,120 @@ elf_get_reloc_upper_bound (abfd, asect)
   return (asect->reloc_count + 1) * sizeof (arelent *);
 }
 
+/* Read in and swap the external relocs.  */
+
 static boolean
-elf_slurp_reloca_table (abfd, asect, symbols)
+elf_slurp_reloc_table (abfd, asect, symbols)
      bfd *abfd;
-     sec_ptr asect;
+     asection *asect;
      asymbol **symbols;
 {
-  Elf_External_Rela *native_relocs;
-  arelent *reloc_cache;
-  arelent *cache_ptr;
-
-  unsigned int idx;
+  struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+  struct bfd_elf_section_data * const d = elf_section_data (asect);
+  PTR allocated = NULL;
+  bfd_byte *native_relocs;
+  arelent *relents;
+  arelent *relent;
+  unsigned int i;
+  int entsize;
 
-  if (asect->relocation)
-    return true;
-  if (asect->reloc_count == 0)
-    return true;
-  if (asect->flags & SEC_CONSTRUCTOR)
+  if (asect->relocation != NULL)
     return true;
 
-  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
-    return false;
-  native_relocs = (Elf_External_Rela *)
-    bfd_alloc (abfd, asect->reloc_count * sizeof (Elf_External_Rela));
-  if (!native_relocs)
+  BFD_ASSERT (asect->rel_filepos == d->rel_hdr.sh_offset
+             && (asect->reloc_count
+                 == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize));
+
+  native_relocs = (bfd_byte *) elf_section_data (asect)->relocs;
+  if (native_relocs == NULL)
     {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-  if (bfd_read ((PTR) native_relocs,
-               sizeof (Elf_External_Rela), asect->reloc_count, abfd)
-      != sizeof (Elf_External_Rela) * asect->reloc_count)
-    return false;
+      allocated = (PTR) malloc (d->rel_hdr.sh_size);
+      if (allocated == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+
+      if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0
+         || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd)
+             != d->rel_hdr.sh_size))
+       goto error_return;
 
-  reloc_cache = (arelent *)
-    bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent)));
+      native_relocs = (bfd_byte *) allocated;
+    }
 
-  if (!reloc_cache)
+  relents = ((arelent *)
+            bfd_alloc (abfd, asect->reloc_count * sizeof (arelent)));
+  if (relents == NULL)
     {
       bfd_set_error (bfd_error_no_memory);
-      return false;
+      goto error_return;
     }
 
-  for (idx = 0; idx < asect->reloc_count; idx++)
-    {
-      Elf_Internal_Rela dst;
-      Elf_External_Rela *src;
+  entsize = d->rel_hdr.sh_entsize;
+  BFD_ASSERT (entsize == sizeof (Elf_External_Rel)
+             || entsize == sizeof (Elf_External_Rela));
 
-      cache_ptr = reloc_cache + idx;
-      src = native_relocs + idx;
-      elf_swap_reloca_in (abfd, src, &dst);
+  for (i = 0, relent = relents;
+       i < asect->reloc_count;
+       i++, relent++, native_relocs += entsize)
+    {
+      Elf_Internal_Rela rela;
+      Elf_Internal_Rel rel;
 
-#ifdef RELOC_PROCESSING
-      RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect);
-#else
-      if (asect->flags & SEC_RELOC)
-       {
-         /* relocatable, so the offset is off of the section */
-         cache_ptr->address = dst.r_offset + asect->vma;
-       }
+      if (entsize == sizeof (Elf_External_Rela))
+       elf_swap_reloca_in (abfd, (Elf_External_Rela *) native_relocs, &rela);
       else
        {
-         /* non-relocatable, so the offset a virtual address */
-         cache_ptr->address = dst.r_offset;
+         elf_swap_reloc_in (abfd, (Elf_External_Rel *) native_relocs, &rel);
+         rela.r_offset = rel.r_offset;
+         rela.r_info = rel.r_info;
+         rela.r_addend = 0;
        }
 
-      /* ELF_R_SYM(dst.r_info) is the symbol table offset.  An offset
-        of zero points to the dummy symbol, which was not read into
-        the symbol table SYMBOLS.  */
-      if (ELF_R_SYM (dst.r_info) == 0)
-       cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+      /* The address of an ELF reloc is section relative for an object
+        file, and absolute for an executable file or shared library.
+        The address of a BFD reloc is always section relative.  */
+      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+       relent->address = rela.r_offset;
+      else
+       relent->address = rela.r_offset - asect->vma;
+
+      if (ELF_R_SYM (rela.r_info) == 0)
+       relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
       else
        {
-         asymbol *s;
+         asymbol **ps, *s;
 
-         cache_ptr->sym_ptr_ptr = symbols + ELF_R_SYM (dst.r_info) - 1;
+         ps = symbols + ELF_R_SYM (rela.r_info) - 1;
+         s = *ps;
 
-         /* Translate any ELF section symbol into a BFD section
-            symbol.  */
-         s = *(cache_ptr->sym_ptr_ptr);
-         if (s->flags & BSF_SECTION_SYM)
-           {
-             cache_ptr->sym_ptr_ptr = s->section->symbol_ptr_ptr;
-             s = *cache_ptr->sym_ptr_ptr;
-             if (s->name == 0 || s->name[0] == 0)
-               abort ();
-           }
+         /* Canonicalize ELF section symbols.  FIXME: Why?  */
+         if ((s->flags & BSF_SECTION_SYM) == 0)
+           relent->sym_ptr_ptr = ps;
+         else
+           relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
        }
-      cache_ptr->addend = dst.r_addend;
 
-      /* Fill in the cache_ptr->howto field from dst.r_type */
-      {
-       struct elf_backend_data *ebd = get_elf_backend_data (abfd);
-       (*ebd->elf_info_to_howto) (abfd, cache_ptr, &dst);
-      }
-#endif
+      relent->addend = rela.r_addend;
+
+      if (entsize == sizeof (Elf_External_Rela))
+       (*ebd->elf_info_to_howto) (abfd, relent, &rela);
+      else
+       (*ebd->elf_info_to_howto_rel) (abfd, relent, &rel);
     }
 
-  asect->relocation = reloc_cache;
+  asect->relocation = relents;
+
+  if (allocated != NULL)
+    free (allocated);
+
   return true;
+
+ error_return:
+  if (allocated != NULL)
+    free (allocated);
+  return false;
 }
 
 #ifdef DEBUG
@@ -3045,129 +3062,7 @@ elf_debug_file (ehdrp)
 }
 #endif
 
-static boolean
-elf_slurp_reloc_table (abfd, asect, symbols)
-     bfd *abfd;
-     sec_ptr asect;
-     asymbol **symbols;
-{
-  Elf_External_Rel *native_relocs;
-  arelent *reloc_cache;
-  arelent *cache_ptr;
-  Elf_Internal_Shdr *data_hdr;
-  bfd_vma data_off;
-  unsigned long data_max;
-  char buf[4];                 /* FIXME -- might be elf64 */
-
-  unsigned int idx;
-
-  if (asect->relocation)
-    return true;
-  if (asect->reloc_count == 0)
-    return true;
-  if (asect->flags & SEC_CONSTRUCTOR)
-    return true;
-
-  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
-    return false;
-  native_relocs = (Elf_External_Rel *)
-    bfd_alloc (abfd, asect->reloc_count * sizeof (Elf_External_Rel));
-  if (!native_relocs)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-  if (bfd_read ((PTR) native_relocs,
-               sizeof (Elf_External_Rel), asect->reloc_count, abfd)
-      != sizeof (Elf_External_Rel) * asect->reloc_count)
-    return false;
-
-  reloc_cache = (arelent *)
-    bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent)));
-
-  if (!reloc_cache)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-
-  /* Get the offset of the start of the segment we are relocating to read in
-     the implicit addend.  */
-  data_hdr = &elf_section_data (asect)->this_hdr;
-  data_off = data_hdr->sh_offset;
-  data_max = data_hdr->sh_size - sizeof (buf) + 1;
-
-#if DEBUG & 2
-  elf_debug_section ("data section", -1, data_hdr);
-#endif
-
-  for (idx = 0; idx < asect->reloc_count; idx++)
-    {
-#ifdef RELOC_PROCESSING
-      Elf_Internal_Rel dst;
-      Elf_External_Rel *src;
-
-      cache_ptr = reloc_cache + idx;
-      src = native_relocs + idx;
-      elf_swap_reloc_in (abfd, src, &dst);
-
-      RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect);
-#else
-      Elf_Internal_Rel dst;
-      Elf_External_Rel *src;
-
-      cache_ptr = reloc_cache + idx;
-      src = native_relocs + idx;
-
-      elf_swap_reloc_in (abfd, src, &dst);
-
-      if (asect->flags & SEC_RELOC)
-       {
-         /* relocatable, so the offset is off of the section */
-         cache_ptr->address = dst.r_offset + asect->vma;
-       }
-      else
-       {
-         /* non-relocatable, so the offset a virtual address */
-         cache_ptr->address = dst.r_offset;
-       }
-
-      /* ELF_R_SYM(dst.r_info) is the symbol table offset.  An offset
-        of zero points to the dummy symbol, which was not read into
-        the symbol table SYMBOLS.  */
-      if (ELF_R_SYM (dst.r_info) == 0)
-       cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
-      else
-       {
-         asymbol *s;
-
-         cache_ptr->sym_ptr_ptr = symbols + ELF_R_SYM (dst.r_info) - 1;
-
-         /* Translate any ELF section symbol into a BFD section
-            symbol.  */
-         s = *(cache_ptr->sym_ptr_ptr);
-         if (s->flags & BSF_SECTION_SYM)
-           {
-             cache_ptr->sym_ptr_ptr = s->section->symbol_ptr_ptr;
-             s = *cache_ptr->sym_ptr_ptr;
-             if (s->name == 0 || s->name[0] == 0)
-               abort ();
-           }
-       }
-      BFD_ASSERT (dst.r_offset <= data_max);
-      cache_ptr->addend = 0;
-
-      /* Fill in the cache_ptr->howto field from dst.r_type */
-      {
-       struct elf_backend_data *ebd = get_elf_backend_data (abfd);
-       (*ebd->elf_info_to_howto_rel) (abfd, cache_ptr, &dst);
-      }
-#endif
-    }
-
-  asect->relocation = reloc_cache;
-  return true;
-}
+/* Canonicalize the relocs.  */
 
 long
 elf_canonicalize_reloc (abfd, section, relptr, symbols)
@@ -3176,28 +3071,18 @@ elf_canonicalize_reloc (abfd, section, relptr, symbols)
      arelent **relptr;
      asymbol **symbols;
 {
-  arelent *tblptr = section->relocation;
-  unsigned int count = 0;
-  int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+  arelent *tblptr;
+  unsigned int i;
 
-  /* snarfed from coffcode.h */
-  if (use_rela_p)
-    {
-      if (! elf_slurp_reloca_table (abfd, section, symbols))
-       return -1;
-    }
-  else
-    {
-      if (! elf_slurp_reloc_table (abfd, section, symbols))
-       return -1;
-    }
+  if (! elf_slurp_reloc_table (abfd, section, symbols))
+    return -1;
 
   tblptr = section->relocation;
-
-  for (; count++ < section->reloc_count;)
+  for (i = 0; i < section->reloc_count; i++)
     *relptr++ = tblptr++;
 
-  *relptr = 0;
+  *relptr = NULL;
+
   return section->reloc_count;
 }
 
@@ -6041,12 +5926,21 @@ elf_link_input_bfd (finfo, input_bfd)
 
       if ((o->flags & SEC_RELOC) != 0)
        {
-         /* Read in the relocs.  */
-         input_rel_hdr = &elf_section_data (o)->rel_hdr;
-         if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_read (finfo->external_relocs, 1, input_rel_hdr->sh_size,
-                          input_bfd) != input_rel_hdr->sh_size)
-           return false;
+         PTR external_relocs;
+
+         /* Get the external relocs.  They may have been cached.  */
+         external_relocs = elf_section_data (o)->relocs;
+         if (external_relocs == NULL)
+           {
+             input_rel_hdr = &elf_section_data (o)->rel_hdr;
+             if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET)
+                  != 0)
+                 || (bfd_read (finfo->external_relocs, 1,
+                              input_rel_hdr->sh_size, input_bfd)
+                     != input_rel_hdr->sh_size))
+               return false;
+             external_relocs = finfo->external_relocs;
+           }
 
          /* Swap in the relocs.  For convenience, we always produce
             an Elf_Internal_Rela array; if the relocs are Rel, we set
@@ -6057,7 +5951,7 @@ elf_link_input_bfd (finfo, input_bfd)
              Elf_External_Rel *erelend;
              Elf_Internal_Rela *irela;
 
-             erel = (Elf_External_Rel *) finfo->external_relocs;
+             erel = (Elf_External_Rel *) external_relocs;
              erelend = erel + o->reloc_count;
              irela = finfo->internal_relocs;
              for (; erel < erelend; erel++, irela++)
@@ -6079,7 +5973,7 @@ elf_link_input_bfd (finfo, input_bfd)
              BFD_ASSERT (input_rel_hdr->sh_entsize
                          == sizeof (Elf_External_Rela));
 
-             erela = (Elf_External_Rela *) finfo->external_relocs;
+             erela = (Elf_External_Rela *) external_relocs;
              erelaend = erela + o->reloc_count;
              irela = finfo->internal_relocs;
              for (; erela < erelaend; erela++, irela++)
index 748e482..84f79bb 100644 (file)
@@ -375,14 +375,29 @@ struct elf_sym_extra
 
 typedef struct elf_sym_extra Elf_Sym_Extra;
 
+/* Information stored for each BFD section in an ELF file.  This
+   structure is allocated by elf_new_section_hook.  */
+
 struct bfd_elf_section_data {
+  /* The ELF header for this section.  */
   Elf_Internal_Shdr this_hdr;
+  /* The ELF header for the reloc section associated with this
+     section, if any.  */
   Elf_Internal_Shdr rel_hdr;
-  int this_idx, rel_idx;
+  /* The ELF section number of this section.  Only used for an output
+     file.  */
+  int this_idx;
+  /* The ELF section number of the reloc section associated with this
+     section, if any.  Only used for an output file.  */
+  int rel_idx;
+  /* Used by the backend linker to store the symbol hash table entries
+     associated with relocs against global symbols.  */
   struct elf_link_hash_entry **rel_hashes;
+  /* A pointer to the unswapped external relocs; this may be NULL.  */
+  PTR relocs;
 };
+
 #define elf_section_data(sec)  ((struct bfd_elf_section_data*)sec->used_by_bfd)
-#define shdr_name(abfd,shdr)   (elf_shstrtab (abfd)->tab + (shdr)->sh_name)
 
 #define get_elf_backend_data(abfd) \
   ((struct elf_backend_data *) (abfd)->xvec->backend_data)