Make MIPS ELF use new ELF backend linker. No shared library
authorIan Lance Taylor <ian@airs.com>
Tue, 24 May 1994 20:44:50 +0000 (20:44 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 24 May 1994 20:44:50 +0000 (20:44 +0000)
support yet.
* elf32-mips.c (bfd_mips_elf32_swap_gptab_in): New function.
(bfd_mips_elf32_swap_gptab_out): New function.
(mips_elf_object_p): If last symbol is LOCAL, set elf_bad_symtab.
(mips_elf_final_write_processing): Set sh_info field for .gptab.*
sections.
(mips_elf_fake_sections): Set sh_entsize for .gptab.* sections.
(mips_elf_read_ecoff_info): Read and free external symbols last,
not first, for clarity.
(struct mips_elf_link_hash_entry): Define new structure.
(struct mips_elf_link_hash_table): Define new structure.
(mips_elf_link_hash_lookup): Define new macro.
(mips_elf_link_hash_traverse): Define new macro.
(mips_elf_hash_table): Define new macro.
(mips_elf_link_hash_newfunc): New static function.
(mips_elf_link_hash_table_create): New static function.
(mips_elf_add_symbol_hook): New static function.
(struct extsym_info): Define new structure.
(mips_elf_get_extr, mips_elf_set_index): Remove.
(mips_elf_output_extsym): New static function.
(gptab_compare): New static function.
(mips_elf_final_link): Rewrite to use ELF backend linker, and to
merge gptab information in input files.
(mips_elf_relocate_hi16): New static function.
(mips_elf_relocate_section): New static function.
(bfd_elf32_bfd_link_hash_table_create): Define as macro before
including elf32-target.h.
(elf_backend_relocate_section): Likewise.
(elf_backend_add_symbol_hook): Likewise.
* elf.c (_bfd_elf_link_hash_newfunc): Rename from
elf_link_hash_newfunc and make globally visible.  Change caller.
(_bfd_elf_link_hash_table_init): New function, broken out of
_bfd_elf_link_hash_table_create.
(_bfd_elf_link_hash_table_create): Use
_bfd_elf_link_hash_table_init.
* libelf.h (struct elf_obj_tdata): Add new field bad_symtab.
(elf_bad_symtab): Define new accessor macro.
(_bfd_elf_link_hash_newfunc): Declare.
(_bew_elf_link_hash_table_init): Declare.
* elfcode.h (elf_object_p): Call backend object_p hook after
swapping in all the section headers.
(map_program_segments): Correct typo: Internal for External.
(elf_link_add_object_symbols): If elf_bad_symtab is set, read all
the symbols.  Skip STB_LOCAL symbols rather than giving an error.
(elf_bfd_final_link): If elf_bad_symtab is set, allocate space for
all symbols, not just locals.
(elf_link_output_extsym): Only skip a symbol not mentioned by a
regular file if it is mentioned by a dynamic object.
(elf_link_input_bfd): If elf_bad_symtab is set, read all the
symbols.

bfd/ChangeLog
bfd/elf.c
bfd/elfcode.h
bfd/libelf.h

index aa8eace0f7a0c1801b12ab642baaa1bbeead8b71..280b40ffed0e3fea9b21b56d9021f4be3244d522 100644 (file)
@@ -1,3 +1,57 @@
+Tue May 24 16:17:18 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
+
+       Make MIPS ELF use new ELF backend linker.  No shared library
+       support yet.
+       * elf32-mips.c (bfd_mips_elf32_swap_gptab_in): New function.
+       (bfd_mips_elf32_swap_gptab_out): New function.
+       (mips_elf_object_p): If last symbol is LOCAL, set elf_bad_symtab.
+       (mips_elf_final_write_processing): Set sh_info field for .gptab.*
+       sections.
+       (mips_elf_fake_sections): Set sh_entsize for .gptab.* sections.
+       (mips_elf_read_ecoff_info): Read and free external symbols last,
+       not first, for clarity.
+       (struct mips_elf_link_hash_entry): Define new structure.
+       (struct mips_elf_link_hash_table): Define new structure.
+       (mips_elf_link_hash_lookup): Define new macro.
+       (mips_elf_link_hash_traverse): Define new macro.
+       (mips_elf_hash_table): Define new macro.
+       (mips_elf_link_hash_newfunc): New static function.
+       (mips_elf_link_hash_table_create): New static function.
+       (mips_elf_add_symbol_hook): New static function.
+       (struct extsym_info): Define new structure.
+       (mips_elf_get_extr, mips_elf_set_index): Remove.
+       (mips_elf_output_extsym): New static function.
+       (gptab_compare): New static function.
+       (mips_elf_final_link): Rewrite to use ELF backend linker, and to
+       merge gptab information in input files.
+       (mips_elf_relocate_hi16): New static function.
+       (mips_elf_relocate_section): New static function.
+       (bfd_elf32_bfd_link_hash_table_create): Define as macro before
+       including elf32-target.h.
+       (elf_backend_relocate_section): Likewise.
+       (elf_backend_add_symbol_hook): Likewise.
+       * elf.c (_bfd_elf_link_hash_newfunc): Rename from
+       elf_link_hash_newfunc and make globally visible.  Change caller.
+       (_bfd_elf_link_hash_table_init): New function, broken out of
+       _bfd_elf_link_hash_table_create.
+       (_bfd_elf_link_hash_table_create): Use
+       _bfd_elf_link_hash_table_init.
+       * libelf.h (struct elf_obj_tdata): Add new field bad_symtab.
+       (elf_bad_symtab): Define new accessor macro.
+       (_bfd_elf_link_hash_newfunc): Declare.
+       (_bew_elf_link_hash_table_init): Declare.
+       * elfcode.h (elf_object_p): Call backend object_p hook after
+       swapping in all the section headers.
+       (map_program_segments): Correct typo: Internal for External.
+       (elf_link_add_object_symbols): If elf_bad_symtab is set, read all
+       the symbols.  Skip STB_LOCAL symbols rather than giving an error.
+       (elf_bfd_final_link): If elf_bad_symtab is set, allocate space for
+       all symbols, not just locals.
+       (elf_link_output_extsym): Only skip a symbol not mentioned by a
+       regular file if it is mentioned by a dynamic object.
+       (elf_link_input_bfd): If elf_bad_symtab is set, read all the
+       symbols.
+
 Fri May 20 13:38:23 1994  Jeff Law  (law@snake.cs.utah.edu)
 
        * som.c (som_set_reloc_info): Do not set any relocation info
index b5c23db365d2759acaecf9b5a4244bc92e8da267..3e1e712f84f5e98753d4e5c09e457da849de6c86 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -301,15 +301,10 @@ bfd_elf_generic_reloc (abfd,
   return bfd_reloc_continue;
 }
 \f
-/* Generic ELF link code.  */
-
-static struct bfd_hash_entry *elf_link_hash_newfunc
-  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
-
 /* Create an entry in an ELF linker hash table.  */
 
-static struct bfd_hash_entry *
-elf_link_hash_newfunc (entry, table, string)
+struct bfd_hash_entry *
+_bfd_elf_link_hash_newfunc (entry, table, string)
      struct bfd_hash_entry *entry;
      struct bfd_hash_table *table;
      const char *string;
@@ -347,6 +342,23 @@ elf_link_hash_newfunc (entry, table, string)
   return (struct bfd_hash_entry *) ret;
 }
 
+/* Initialize an ELF linker hash table.  */
+
+boolean
+_bfd_elf_link_hash_table_init (table, abfd, newfunc)
+     struct elf_link_hash_table *table;
+     bfd *abfd;
+     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+                                               struct bfd_hash_table *,
+                                               const char *));
+{
+  table->dynobj = NULL;
+  table->dynsymcount = 0;
+  table->dynstr = NULL;
+  table->bucketcount = 0;
+  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
 /* Create an ELF linker hash table.  */
 
 struct bfd_link_hash_table *
@@ -362,17 +374,12 @@ _bfd_elf_link_hash_table_create (abfd)
       bfd_set_error (bfd_error_no_memory);
       return NULL;
     }
-  if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  elf_link_hash_newfunc))
+
+  if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
     {
       bfd_release (abfd, ret);
       return NULL;
     }
 
-  ret->dynobj = NULL;
-  ret->dynsymcount = 0;
-  ret->dynstr = NULL;
-  ret->bucketcount = 0;
-
   return &ret->root;
 }
index db0316aac18732b262869600b75b08c9dedf8cd9..21deffdf167af71ded7f551c97ac83aa09b9daa6 100644 (file)
@@ -939,14 +939,6 @@ elf_object_p (abfd)
   /* Remember the entry point specified in the ELF file header. */
   bfd_get_start_address (abfd) = i_ehdrp->e_entry;
 
-  /* Let the backend double check the format and override global
-     information.  */
-  if (ebd->elf_backend_object_p)
-    {
-      if ((*ebd->elf_backend_object_p) (abfd) == false)
-       goto got_wrong_format_error;
-    }
-
   /* Allocate space for a copy of the section header table in
      internal form, seek to the section header table in the file,
      read it in, and convert it to internal form.  */
@@ -997,6 +989,14 @@ elf_object_p (abfd)
        goto got_no_match;
     }
 
+  /* Let the backend double check the format and override global
+     information.  */
+  if (ebd->elf_backend_object_p)
+    {
+      if ((*ebd->elf_backend_object_p) (abfd) == false)
+       goto got_wrong_format_error;
+    }
+
   return (abfd->xvec);
 
 got_wrong_format_error:
@@ -1914,7 +1914,7 @@ map_program_segments (abfd, off, first, phdr_size)
 
   /* Make sure the return value from get_program_header_size matches
      what we computed here.  */
-  if (phdr_count != phdr_size / sizeof (Elf_Internal_Phdr))
+  if (phdr_count != phdr_size / sizeof (Elf_External_Phdr))
     abort ();
 
   /* Set up program header information.  */
@@ -4111,6 +4111,7 @@ elf_link_add_object_symbols (abfd, info)
   Elf_Internal_Shdr *hdr;
   size_t symcount;
   size_t extsymcount;
+  size_t extsymoff;
   Elf_External_Sym *buf = NULL;
   struct elf_link_hash_entry **sym_hash;
   boolean dynamic;
@@ -4128,7 +4129,16 @@ elf_link_add_object_symbols (abfd, info)
   /* The sh_info field of the symtab header tells us where the
      external symbols start.  We don't care about the local symbols at
      this point.  */
-  extsymcount = symcount - hdr->sh_info;
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
 
   buf = (Elf_External_Sym *) malloc (extsymcount * sizeof (Elf_External_Sym));
   if (buf == NULL && extsymcount != 0)
@@ -4251,7 +4261,7 @@ elf_link_add_object_symbols (abfd, info)
     }
 
   if (bfd_seek (abfd,
-               hdr->sh_offset + hdr->sh_info * sizeof (Elf_External_Sym),
+               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)))
@@ -4283,9 +4293,9 @@ elf_link_add_object_symbols (abfd, info)
        {
          /* This should be impossible, since ELF requires that all
             global symbols follow all local symbols, and that sh_info
-            point to the first global symbol.  */
-         bfd_set_error (bfd_error_bad_value);
-         goto error_return;
+            point to the first global symbol.  Unfortunatealy, Irix 5
+            screws this up.  */
+         continue;
        }
       else if (bind == STB_GLOBAL)
        flags = BSF_GLOBAL;
@@ -5093,10 +5103,19 @@ elf_bfd_final_link (abfd, info)
 
              /* We are interested in just local symbols, not all
                 symbols.  */
-             if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
-                 && (elf_tdata (sec->owner)->symtab_hdr.sh_info
-                     > max_sym_count))
-               max_sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info;
+             if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour)
+               {
+                 size_t sym_count;
+
+                 if (elf_bad_symtab (sec->owner))
+                   sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size
+                                / sizeof (Elf_External_Sym));
+                 else
+                   sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info;
+
+                 if (sym_count > max_sym_count)
+                   max_sym_count = sym_count;
+               }
 
              if ((sec->flags & SEC_RELOC) != 0)
                {
@@ -5688,7 +5707,9 @@ elf_link_output_extsym (h, data)
      output it.  */
   if (h->indx == -2)
     strip = false;
-  else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+  else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+           || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)
+          && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
           && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
     strip = true;
   else if (finfo->info->strip == strip_all
@@ -5843,6 +5864,8 @@ elf_link_input_bfd (finfo, input_bfd)
                                       asection **));
   bfd *output_bfd;
   Elf_Internal_Shdr *symtab_hdr;
+  size_t locsymcount;
+  size_t extsymoff;
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
   Elf_Internal_Sym *isym;
@@ -5860,18 +5883,29 @@ elf_link_input_bfd (finfo, input_bfd)
   if (elf_elfheader (input_bfd)->e_type == ET_DYN)
     return true;
 
-  /* Read the local symbols.  */
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  if (elf_bad_symtab (input_bfd))
+    {
+      locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+      extsymoff = 0;
+    }
+  else
+    {
+      locsymcount = symtab_hdr->sh_info;
+      extsymoff = symtab_hdr->sh_info;
+    }
+
+  /* Read the local symbols.  */
   if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
       || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym),
-                   symtab_hdr->sh_info, input_bfd)
-         != symtab_hdr->sh_info * sizeof (Elf_External_Sym)))
+                   locsymcount, input_bfd)
+         != locsymcount * sizeof (Elf_External_Sym)))
     return false;
 
   /* Swap in the local symbols and write out the ones which we know
      are going into the output file.  */
   esym = finfo->external_syms;
-  esymend = esym + symtab_hdr->sh_info;
+  esymend = esym + locsymcount;
   isym = finfo->internal_syms;
   pindex = finfo->indices;
   ppsection = finfo->sections;
@@ -5884,6 +5918,15 @@ elf_link_input_bfd (finfo, input_bfd)
       elf_swap_symbol_in (input_bfd, esym, isym);
       *pindex = -1;
 
+      if (elf_bad_symtab (input_bfd))
+       {
+         if (ELF_ST_BIND (isym->st_info) != STB_LOCAL)
+           {
+             *ppsection = NULL;
+             continue;
+           }
+       }
+
       if (isym->st_shndx == SHN_UNDEF)
        isec = &bfd_und_section;
       else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
@@ -6084,7 +6127,9 @@ elf_link_input_bfd (finfo, input_bfd)
                  if (r_symndx == 0)
                    continue;
 
-                 if (r_symndx >= symtab_hdr->sh_info)
+                 if (r_symndx >= locsymcount
+                     || (elf_bad_symtab (input_bfd)
+                         && finfo->sections[r_symndx] == NULL))
                    {
                      long indx;
 
@@ -6095,7 +6140,7 @@ elf_link_input_bfd (finfo, input_bfd)
                         reloc to point to the global hash table entry
                         for this symbol.  The symbol index is then
                         set at the end of elf_bfd_final_link.  */
-                     indx = r_symndx - symtab_hdr->sh_info;
+                     indx = r_symndx - extsymoff;
                      *rel_hash = elf_sym_hashes (input_bfd)[indx];
 
                      /* Setting the index to -2 tells
index 25d56b05cb82f6416c4f11402203c6cc24c5d2cc..6850abaf5f2913e20b00686e75232c74c28eb2c4 100644 (file)
@@ -416,6 +416,13 @@ struct elf_obj_tdata
      table, used when linking.  This is indexed by the symbol index
      minus the sh_info field of the symbol table header.  */
   struct elf_link_hash_entry **sym_hashes;
+
+  /* Irix 5 often screws up the symbol table, sorting local symbols
+     after global symbols.  This flag is set if the symbol table in
+     this BFD appears to be screwed up.  If it is, we ignore the
+     sh_info field in the symbol table header, and always read all the
+     symbols.  */
+  boolean bad_symtab;
 };
 
 #define elf_tdata(bfd)         ((bfd) -> tdata.elf_obj_data)
@@ -434,6 +441,7 @@ struct elf_obj_tdata
 #define elf_gp(bfd)            (elf_tdata(bfd) -> gp)
 #define elf_gp_size(bfd)       (elf_tdata(bfd) -> gp_size)
 #define elf_sym_hashes(bfd)    (elf_tdata(bfd) -> sym_hashes)
+#define elf_bad_symtab(bfd)    (elf_tdata(bfd) -> bad_symtab)
 \f
 extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned));
 extern char * elf_get_str_section PARAMS ((bfd *, unsigned));
@@ -455,8 +463,15 @@ extern boolean bfd_elf_mkobject PARAMS ((bfd *));
 extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *));
 extern boolean _bfd_elf_make_section_from_shdr
   PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, const char *name));
+extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create
   PARAMS ((bfd *));
+extern boolean _bfd_elf_link_hash_table_init
+  PARAMS ((struct elf_link_hash_table *, bfd *,
+          struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+                                      struct bfd_hash_table *,
+                                      const char *)));
 
 extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *));
 extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *));