* configure: Ignore new autoconf configure options.
[binutils-gdb.git] / bfd / elf32-mips.c
index d8c24de6054cc1fdbc271244b6591cc47ade6723..118ebb07b39a3df3f8c5b8c7cee4e485628f6b9c 100644 (file)
@@ -1,5 +1,5 @@
 /* MIPS-specific support for 32-bit ELF
-   Copyright 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -18,14 +18,14 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
 #include "bfdlink.h"
 #include "genlink.h"
-#include "libelf.h"
+#include "elf-bfd.h"
 #include "elf/mips.h"
 
 /* Get the ECOFF swapping routines.  */
@@ -84,6 +84,11 @@ static boolean mips_elf_section_processing
 static void mips_elf_symbol_processing PARAMS ((bfd *, asymbol *));
 static boolean mips_elf_read_ecoff_info
   PARAMS ((bfd *, asection *, struct ecoff_debug_info *));
+static boolean mips_elf_is_local_label
+  PARAMS ((bfd *, asymbol *));
+static boolean mips_elf_find_nearest_line
+  PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **,
+          const char **, unsigned int *));
 static struct bfd_hash_entry *mips_elf_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static struct bfd_link_hash_table *mips_elf_link_hash_table_create
@@ -686,6 +691,10 @@ mips_elf_got16_reloc (abfd,
    cleverly because the entries in the .lit8 and .lit4 sections can be
    merged.  */
 
+static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *,
+                                                     arelent *, asection *,
+                                                     boolean, PTR, bfd_vma));
+
 static bfd_reloc_status_type
 mips_elf_gprel16_reloc (abfd,
                        reloc_entry,
@@ -703,9 +712,6 @@ mips_elf_gprel16_reloc (abfd,
      char **error_message;
 {
   boolean relocateable;
-  bfd_vma relocation;
-  unsigned long val;
-  unsigned long insn;
 
   /* If we're relocating, and this is an external symbol with no
      addend, we don't want to change anything.  We will only have an
@@ -731,6 +737,10 @@ mips_elf_gprel16_reloc (abfd,
       && relocateable == false)
     return bfd_reloc_undefined;
 
+  /* Some of the code below assumes the output bfd is ELF too.  */
+  if (output_bfd->xvec->flavour != bfd_target_elf_flavour)
+    abort ();
+
   /* We have to figure out the gp value, so that we can adjust the
      symbol value correctly.  We look up the symbol _gp in the output
      BFD.  If we can't find it, we're stuck.  We cache it in the ELF
@@ -783,6 +793,25 @@ mips_elf_gprel16_reloc (abfd,
        }
     }
 
+  return gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
+                         relocateable, data, elf_gp (output_bfd));
+}
+
+static bfd_reloc_status_type
+gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
+                gp)
+     bfd *abfd;
+     asymbol *symbol;
+     arelent *reloc_entry;
+     asection *input_section;
+     boolean relocateable;
+     PTR data;
+     bfd_vma gp;
+{
+  bfd_vma relocation;
+  unsigned long insn;
+  unsigned long val;
+
   if (bfd_is_com_section (symbol->section))
     relocation = 0;
   else
@@ -806,7 +835,7 @@ mips_elf_gprel16_reloc (abfd,
      an external symbol.  */
   if (relocateable == false
       || (symbol->flags & BSF_SECTION_SYM) != 0)
-    val += relocation - elf_gp (output_bfd);
+    val += relocation - gp;
 
   insn = (insn &~ 0xffff) | (val & 0xffff);
   bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
@@ -853,7 +882,7 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
      bfd *abfd;
      bfd_reloc_code_real_type code;
 {
-  int i;
+  unsigned int i;
 
   for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++)
     {
@@ -989,27 +1018,8 @@ mips_elf_object_p (abfd)
 
   /* Irix 5 is broken.  Object file symbol tables are not always
      sorted correctly such that local symbols precede global symbols,
-     and the sh_info field in the symbol table is not always right.
-     We try to quickly check whether the symbol table is broken for
-     this BFD, and, if it is, we set elf_bad_symtab in tdata.  */
-  if (elf_onesymtab (abfd) != 0)
-    {
-      Elf_Internal_Shdr *symtab_hdr;
-      Elf32_External_Sym esym;
-
-      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-      if (bfd_seek (abfd,
-                   (symtab_hdr->sh_offset
-                    + symtab_hdr->sh_size
-                    - sizeof (Elf32_External_Sym)),
-                   SEEK_SET) != 0
-         || (bfd_read ((PTR) &esym, 1, sizeof (Elf32_External_Sym), abfd)
-             != sizeof (Elf32_External_Sym)))
-       return false;
-      if (ELF_ST_BIND (bfd_h_get_8 (abfd, (bfd_byte *) esym.st_info))
-         == STB_LOCAL)
-       elf_bad_symtab (abfd) = true;
-    }
+     and the sh_info field in the symbol table is not always right.  */
+  elf_bad_symtab (abfd) = true;
 
   return true;
 }
@@ -1342,7 +1352,7 @@ mips_elf_symbol_processing (abfd, asym)
        {
          /* Initialize the acommon section.  */
          mips_elf_acom_section.name = ".acommon";
-         mips_elf_acom_section.flags = SEC_NO_FLAGS;
+         mips_elf_acom_section.flags = SEC_ALLOC;
          mips_elf_acom_section.output_section = &mips_elf_acom_section;
          mips_elf_acom_section.symbol = &mips_elf_acom_symbol;
          mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr;
@@ -1399,7 +1409,7 @@ mips_elf_read_ecoff_info (abfd, section, debug)
 
   swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
 
-  ext_hdr = (char *) malloc (swap->external_hdr_size);
+  ext_hdr = (char *) malloc ((size_t) swap->external_hdr_size);
   if (ext_hdr == NULL && swap->external_hdr_size != 0)
     {
       bfd_set_error (bfd_error_no_memory);
@@ -1421,7 +1431,7 @@ mips_elf_read_ecoff_info (abfd, section, debug)
     debug->ptr = NULL;                                                 \
   else                                                                 \
     {                                                                  \
-      debug->ptr = (type) malloc (size * symhdr->count);               \
+      debug->ptr = (type) malloc ((size_t) (size * symhdr->count));    \
       if (debug->ptr == NULL)                                          \
        {                                                               \
          bfd_set_error (bfd_error_no_memory);                          \
@@ -1479,7 +1489,125 @@ mips_elf_read_ecoff_info (abfd, section, debug)
     free (debug->external_ext);
   return false;
 }
+\f
+/* MIPS ELF local labels start with '$', not 'L'.  */
+
+/*ARGSUSED*/
+static boolean
+mips_elf_is_local_label (abfd, symbol)
+     bfd *abfd;
+     asymbol *symbol;
+{
+  return symbol->name[0] == '$';
+}
+
+/* MIPS ELF uses a special find_nearest_line routine in order the
+   handle the ECOFF debugging information.  */
+
+struct mips_elf_find_line
+{
+  struct ecoff_debug_info d;
+  struct ecoff_find_line i;
+};
+
+static boolean
+mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+                           functionname_ptr, line_ptr)
+     bfd *abfd;
+     asection *section;
+     asymbol **symbols;
+     bfd_vma offset;
+     const char **filename_ptr;
+     const char **functionname_ptr;
+     unsigned int *line_ptr;
+{
+  asection *msec;
+
+  msec = bfd_get_section_by_name (abfd, ".mdebug");
+  if (msec != NULL)
+    {
+      flagword origflags;
+      struct mips_elf_find_line *fi;
+      const struct ecoff_debug_swap * const swap =
+       get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+
+      /* If we are called during a link, mips_elf_final_link may have
+        cleared the SEC_HAS_CONTENTS field.  We force it back on here
+        if appropriate (which it normally will be).  */
+      origflags = msec->flags;
+      if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS)
+       msec->flags |= SEC_HAS_CONTENTS;
+
+      fi = elf_tdata (abfd)->find_line_info;
+      if (fi == NULL)
+       {
+         bfd_size_type external_fdr_size;
+         char *fraw_src;
+         char *fraw_end;
+         struct fdr *fdr_ptr;
+
+         fi = ((struct mips_elf_find_line *)
+               bfd_alloc (abfd, sizeof (struct mips_elf_find_line)));
+         if (fi == NULL)
+           {
+             msec->flags = origflags;
+             return false;
+           }
+
+         memset (fi, 0, sizeof (struct mips_elf_find_line));
+
+         if (! mips_elf_read_ecoff_info (abfd, msec, &fi->d))
+           {
+             msec->flags = origflags;
+             return false;
+           }
+
+         /* Swap in the FDR information.  */
+         fi->d.fdr = ((struct fdr *)
+                      bfd_alloc (abfd,
+                                 (fi->d.symbolic_header.ifdMax *
+                                  sizeof (struct fdr))));
+         if (fi->d.fdr == NULL)
+           {
+             msec->flags = origflags;
+             return false;
+           }
+         external_fdr_size = swap->external_fdr_size;
+         fdr_ptr = fi->d.fdr;
+         fraw_src = (char *) fi->d.external_fdr;
+         fraw_end = (fraw_src
+                     + fi->d.symbolic_header.ifdMax * external_fdr_size);
+         for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
+           (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+
+         elf_tdata (abfd)->find_line_info = fi;
+
+         /* Note that we don't bother to ever free this information.
+             find_nearest_line is either called all the time, as in
+             objdump -l, so the information should be saved, or it is
+             rarely called, as in ld error messages, so the memory
+             wasted is unimportant.  Still, it would probably be a
+             good idea for free_cached_info to throw it away.  */
+       }
+
+      if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
+                                 &fi->i, filename_ptr, functionname_ptr,
+                                 line_ptr))
+       {
+         msec->flags = origflags;
+         return true;
+       }
 
+      msec->flags = origflags;
+    }
+
+  /* Fall back on the generic ELF find_nearest_line routine.  */
+
+  return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
+                                    filename_ptr, functionname_ptr,
+                                    line_ptr);
+}
+\f
 /* The MIPS ELF linker needs additional information for each symbol in
    the global hash table.  */
 
@@ -1539,10 +1667,7 @@ mips_elf_link_hash_newfunc (entry, table, string)
           bfd_hash_allocate (table,
                              sizeof (struct mips_elf_link_hash_entry)));
   if (ret == (struct mips_elf_link_hash_entry *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_hash_entry *) ret;
-    }
+    return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct mips_elf_link_hash_entry *)
@@ -1571,10 +1696,7 @@ mips_elf_link_hash_table_create (abfd)
   ret = ((struct mips_elf_link_hash_table *)
         bfd_alloc (abfd, sizeof (struct mips_elf_link_hash_table)));
   if (ret == (struct mips_elf_link_hash_table *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
 
   if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
                                       mips_elf_link_hash_newfunc))
@@ -1684,7 +1806,8 @@ mips_elf_output_extsym (h, data)
       h->esym.asym.value = 0;
       h->esym.asym.st = stGlobal;
 
-      if (h->root.root.type != bfd_link_hash_defined)
+      if (h->root.root.type != bfd_link_hash_defined
+         && h->root.root.type != bfd_link_hash_defweak)
        h->esym.asym.sc = scAbs;
       else
        {
@@ -1721,7 +1844,8 @@ mips_elf_output_extsym (h, data)
 
   if (h->root.root.type == bfd_link_hash_common)
     h->esym.asym.value = h->root.root.u.c.size;
-  else if (h->root.root.type == bfd_link_hash_defined)
+  else if (h->root.root.type == bfd_link_hash_defined
+          || h->root.root.type == bfd_link_hash_defweak)
     {
       asection *sec;
 
@@ -1829,8 +1953,12 @@ mips_elf_final_link (abfd, info)
 
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
-             BFD_ASSERT (input_section->_raw_size
-                         == sizeof (Elf32_External_RegInfo));
+
+             /* The linker emulation code has probably clobbered the
+                 size to be zero bytes.  */
+             if (input_section->_raw_size == 0)
+               input_section->_raw_size = sizeof (Elf32_External_RegInfo);
+
              if (! bfd_get_section_contents (input_bfd, input_section,
                                              (PTR) &ext,
                                              (file_ptr) 0,
@@ -2090,6 +2218,9 @@ mips_elf_final_link (abfd, info)
            gptab_bss_sec = o;
          else
            {
+             (*_bfd_error_handler)
+               ("%s: illegal section name `%s'",
+                bfd_get_filename (abfd), o->name);
              bfd_set_error (bfd_error_nonrepresentable_section);
              return false;
            }
@@ -2236,7 +2367,6 @@ mips_elf_final_link (abfd, info)
                     bfd_alloc (abfd, c * sizeof (Elf32_External_gptab)));
          if (ext_tab == NULL)
            {
-             bfd_set_error (bfd_error_no_memory);
              free (tab);
              return false;
            }
@@ -2407,7 +2537,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
     {
       int r_type;
       reloc_howto_type *howto;
-      long r_symndx;
+      unsigned long r_symndx;
       bfd_vma addend;
       struct elf_link_hash_entry *h;
       asection *sec;
@@ -2546,14 +2676,15 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              indx = r_symndx - extsymoff;
              h = elf_sym_hashes (input_bfd)[indx];
-             if (h->root.type == bfd_link_hash_defined)
+             if (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak)
                {
                  sec = h->root.u.def.section;
                  relocation = (h->root.u.def.value
                                + sec->output_section->vma
                                + sec->output_offset);
                }
-             else if (h->root.type == bfd_link_hash_weak)
+             else if (h->root.type == bfd_link_hash_undefweak)
                relocation = 0;
              else
                {
@@ -2594,9 +2725,9 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  name = h->root.root.string;
                else
                  {
-                   name = elf_string_from_elf_section (input_bfd,
-                                                       symtab_hdr->sh_link,
-                                                       sym->st_name);
+                   name = bfd_elf_string_from_elf_section (input_bfd,
+                                                           symtab_hdr->sh_link,
+                                                           sym->st_name);
                    if (name == NULL)
                      return false;
                    if (*name == '\0')
@@ -2615,6 +2746,191 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   return true;
 }
 \f
+/* This is almost identical to bfd_generic_get_... except that some
+   MIPS relocations need to be handled specially.  Sigh.  */
+static bfd_byte *
+elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data,
+                                          relocateable, symbols)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+     struct bfd_link_order *link_order;
+     bfd_byte *data;
+     boolean relocateable;
+     asymbol **symbols;
+{
+  /* Get enough memory to hold the stuff */
+  bfd *input_bfd = link_order->u.indirect.section->owner;
+  asection *input_section = link_order->u.indirect.section;
+
+  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+  arelent **reloc_vector = NULL;
+  long reloc_count;
+
+  if (reloc_size < 0)
+    goto error_return;
+
+  reloc_vector = (arelent **) malloc (reloc_size);
+  if (reloc_vector == NULL && reloc_size != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+
+  /* read in the section */
+  if (!bfd_get_section_contents (input_bfd,
+                                input_section,
+                                (PTR) data,
+                                0,
+                                input_section->_raw_size))
+    goto error_return;
+
+  /* We're not relaxing the section, so just copy the size info */
+  input_section->_cooked_size = input_section->_raw_size;
+  input_section->reloc_done = true;
+
+  reloc_count = bfd_canonicalize_reloc (input_bfd,
+                                       input_section,
+                                       reloc_vector,
+                                       symbols);
+  if (reloc_count < 0)
+    goto error_return;
+
+  if (reloc_count > 0)
+    {
+      arelent **parent;
+      /* for mips */
+      int gp_found;
+      bfd_vma gp = 0x12345678; /* initialize just to shut gcc up */
+
+      {
+       struct bfd_hash_entry *h;
+       struct bfd_link_hash_entry *lh;
+       /* Skip all this stuff if we aren't mixing formats.  */
+       if (abfd && input_bfd
+           && abfd->xvec == input_bfd->xvec)
+         lh = 0;
+       else
+         {
+           h = bfd_hash_lookup (&link_info->hash->table, "_gp", false, false);
+           lh = (struct bfd_link_hash_entry *) h;
+         }
+      lookup:
+       if (lh)
+         {
+           switch (lh->type)
+             {
+             case bfd_link_hash_undefined:
+             case bfd_link_hash_undefweak:
+             case bfd_link_hash_common:
+               gp_found = 0;
+               break;
+             case bfd_link_hash_defined:
+             case bfd_link_hash_defweak:
+               gp_found = 1;
+               gp = lh->u.def.value;
+               break;
+             case bfd_link_hash_indirect:
+             case bfd_link_hash_warning:
+               lh = lh->u.i.link;
+               /* @@FIXME  ignoring warning for now */
+               goto lookup;
+             case bfd_link_hash_new:
+             default:
+               abort ();
+             }
+         }
+       else
+         gp_found = 0;
+      }
+      /* end mips */
+      for (parent = reloc_vector; *parent != (arelent *) NULL;
+          parent++)
+       {
+         char *error_message = (char *) NULL;
+         bfd_reloc_status_type r;
+
+         /* Specific to MIPS: Deal with relocation types that require
+            knowing the gp of the output bfd.  */
+         asymbol *sym = *(*parent)->sym_ptr_ptr;
+         if (bfd_is_abs_section (sym->section) && abfd)
+           {
+             /* The special_function wouldn't get called anyways.  */
+           }
+         else if (!gp_found)
+           {
+             /* The gp isn't there; let the special function code
+                fall over on its own.  */
+           }
+         else if ((*parent)->howto->special_function == mips_elf_gprel16_reloc)
+           {
+             /* bypass special_function call */
+             r = gprel16_with_gp (input_bfd, sym, *parent, input_section,
+                                  relocateable, (PTR) data, gp);
+             goto skip_bfd_perform_relocation;
+           }
+         /* end mips specific stuff */
+
+         r = bfd_perform_relocation (input_bfd,
+                                     *parent,
+                                     (PTR) data,
+                                     input_section,
+                                     relocateable ? abfd : (bfd *) NULL,
+                                     &error_message);
+       skip_bfd_perform_relocation:
+
+         if (relocateable)
+           {
+             asection *os = input_section->output_section;
+
+             /* A partial link, so keep the relocs */
+             os->orelocation[os->reloc_count] = *parent;
+             os->reloc_count++;
+           }
+
+         if (r != bfd_reloc_ok)
+           {
+             switch (r)
+               {
+               case bfd_reloc_undefined:
+                 if (!((*link_info->callbacks->undefined_symbol)
+                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                        input_bfd, input_section, (*parent)->address)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_dangerous:
+                 BFD_ASSERT (error_message != (char *) NULL);
+                 if (!((*link_info->callbacks->reloc_dangerous)
+                       (link_info, error_message, input_bfd, input_section,
+                        (*parent)->address)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_overflow:
+                 if (!((*link_info->callbacks->reloc_overflow)
+                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                        (*parent)->howto->name, (*parent)->addend,
+                        input_bfd, input_section, (*parent)->address)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_outofrange:
+               default:
+                 abort ();
+                 break;
+               }
+
+           }
+       }
+    }
+  if (reloc_vector != NULL)
+    free (reloc_vector);
+  return data;
+
+error_return:
+  if (reloc_vector != NULL)
+    free (reloc_vector);
+  return NULL;
+}
+#define bfd_elf32_bfd_get_relocated_section_contents elf32_mips_get_relocated_section_contents
+\f
 /* ECOFF swapping routines.  These are used when dealing with the
    .mdebug section, which is in the ECOFF debugging format.  */
 static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
@@ -2680,6 +2996,9 @@ static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
                                        mips_elf_final_write_processing
 #define elf_backend_ecoff_debug_swap   &mips_elf_ecoff_debug_swap
 
+#define bfd_elf32_bfd_is_local_label   mips_elf_is_local_label
+#define bfd_elf32_find_nearest_line    mips_elf_find_nearest_line
+
 #define bfd_elf32_bfd_link_hash_table_create \
                                        mips_elf_link_hash_table_create
 #define bfd_elf32_bfd_final_link       mips_elf_final_link