* config/tc-mips.c (mips_cpu_info_table): Add 74K configurations.
[external/binutils.git] / bfd / elfxx-mips.c
index 5483cf2..d9a277b 100644 (file)
@@ -493,7 +493,7 @@ static bfd_boolean mips_elf_sort_hash_table_f
   (struct mips_elf_link_hash_entry *, void *);
 static bfd_vma mips_elf_high
   (bfd_vma);
-static bfd_boolean mips_elf_stub_section_p
+static bfd_boolean mips16_stub_section_p
   (bfd *, asection *);
 static bfd_boolean mips_elf_create_dynamic_relocation
   (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
@@ -709,6 +709,10 @@ static bfd *reldyn_sorting_bfd;
 #define FN_STUB ".mips16.fn."
 #define CALL_STUB ".mips16.call."
 #define CALL_FP_STUB ".mips16.call.fp."
+
+#define FN_STUB_P(name) CONST_STRNEQ (name, FN_STUB)
+#define CALL_STUB_P(name) CONST_STRNEQ (name, CALL_STUB)
+#define CALL_FP_STUB_P(name) CONST_STRNEQ (name, CALL_FP_STUB)
 \f
 /* The format of the first PLT entry in a VxWorks executable.  */
 static const bfd_vma mips_vxworks_exec_plt0_entry[] = {
@@ -3105,8 +3109,7 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
   if (tcount > 0)
     {
       unsigned int primary_total = lcount + tcount + arg->global_count;
-      if (primary_total * MIPS_ELF_GOT_SIZE (bfd2got->bfd)
-         >= MIPS_ELF_GOT_MAX_SIZE (arg->info))
+      if (primary_total > maxcnt)
        too_many_for_tls = TRUE;
     }
 
@@ -4079,9 +4082,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
      a stub.  */
   if (r_type != R_MIPS16_26 && !info->relocatable
       && ((h != NULL && h->fn_stub != NULL)
-         || (local_p && elf_tdata (input_bfd)->local_stubs != NULL
+         || (local_p
+             && elf_tdata (input_bfd)->local_stubs != NULL
              && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
-      && !mips_elf_stub_section_p (input_bfd, input_section))
+      && !mips16_stub_section_p (input_bfd, input_section))
     {
       /* This is a 32- or 64-bit call to a 16-bit function.  We should
         have already noticed that we were going to need the
@@ -4102,33 +4106,40 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
      need to redirect the call to the stub.  */
   else if (r_type == R_MIPS16_26 && !info->relocatable
           && h != NULL
-          && (h->call_stub != NULL || h->call_fp_stub != NULL)
+          && ((h->call_stub != NULL || h->call_fp_stub != NULL)
+              || (local_p
+                  && elf_tdata (input_bfd)->local_call_stubs != NULL
+                  && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
           && !target_is_16_bit_code_p)
     {
-      /* If both call_stub and call_fp_stub are defined, we can figure
-        out which one to use by seeing which one appears in the input
-        file.  */
-      if (h->call_stub != NULL && h->call_fp_stub != NULL)
+      if (local_p)
+       sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx];
+      else
        {
-         asection *o;
-
-         sec = NULL;
-         for (o = input_bfd->sections; o != NULL; o = o->next)
+         /* If both call_stub and call_fp_stub are defined, we can figure
+            out which one to use by checking which one appears in the input
+            file.  */
+         if (h->call_stub != NULL && h->call_fp_stub != NULL)
            {
-             if (CONST_STRNEQ (bfd_get_section_name (input_bfd, o),
-                               CALL_FP_STUB))
+             asection *o;
+             
+             sec = NULL;
+             for (o = input_bfd->sections; o != NULL; o = o->next)
                {
-                 sec = h->call_fp_stub;
-                 break;
+                 if (CALL_FP_STUB_P (bfd_get_section_name (input_bfd, o)))
+                   {
+                     sec = h->call_fp_stub;
+                     break;
+                   }
                }
+             if (sec == NULL)
+               sec = h->call_stub;
            }
-         if (sec == NULL)
+         else if (h->call_stub != NULL)
            sec = h->call_stub;
-       }
-      else if (h->call_stub != NULL)
-       sec = h->call_stub;
-      else
-       sec = h->call_fp_stub;
+         else
+           sec = h->call_fp_stub;
+       }
 
       BFD_ASSERT (sec->size > 0);
       symbol = sec->output_section->vma + sec->output_offset;
@@ -4312,6 +4323,11 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
                                                   input_section))
            return bfd_reloc_undefined;
        }
+      else if (r_symndx == 0)
+       /* r_symndx will be zero only for relocs against symbols
+          from removed linkonce sections, or sections discarded by
+          a linker script.  */
+       value = 0;
       else
        {
          if (r_type != R_MIPS_REL32)
@@ -4703,13 +4719,11 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
 /* Returns TRUE if SECTION is a MIPS16 stub section.  */
 
 static bfd_boolean
-mips_elf_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
+mips16_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
 {
   const char *name = bfd_get_section_name (abfd, section);
 
-  return (CONST_STRNEQ (name, FN_STUB)
-         || CONST_STRNEQ (name, CALL_STUB)
-         || CONST_STRNEQ (name, CALL_FP_STUB));
+  return FN_STUB_P (name) || CALL_STUB_P (name) || CALL_FP_STUB_P (name);
 }
 \f
 /* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
@@ -6138,7 +6152,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   /* Check for the mips16 stub sections.  */
 
   name = bfd_get_section_name (abfd, sec);
-  if (CONST_STRNEQ (name, FN_STUB))
+  if (FN_STUB_P (name))
     {
       unsigned long r_symndx;
 
@@ -6163,9 +6177,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
-                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), FN_STUB)
-                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), CALL_STUB)
-                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), CALL_FP_STUB))
+                 || mips16_stub_section_p (abfd, o))
                continue;
 
              sec_relocs
@@ -6217,6 +6229,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              elf_tdata (abfd)->local_stubs = n;
            }
 
+         sec->flags |= SEC_KEEP;
          elf_tdata (abfd)->local_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
@@ -6237,12 +6250,23 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          /* H is the symbol this stub is for.  */
 
+         /* If we already have an appropriate stub for this function, we
+            don't need another one, so we can discard this one.  Since
+            this function is called before the linker maps input sections
+            to output sections, we can easily discard it by setting the
+            SEC_EXCLUDE flag.  */
+         if (h->fn_stub != NULL)
+           {
+             sec->flags |= SEC_EXCLUDE;
+             return TRUE;
+           }
+
+         sec->flags |= SEC_KEEP;
          h->fn_stub = sec;
          mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
        }
     }
-  else if (CONST_STRNEQ (name, CALL_STUB)
-          || CONST_STRNEQ (name, CALL_FP_STUB))
+  else if (CALL_STUB_P (name) || CALL_FP_STUB_P (name))
     {
       unsigned long r_symndx;
       struct mips_elf_link_hash_entry *h;
@@ -6256,42 +6280,106 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < extsymoff
          || sym_hashes[r_symndx - extsymoff] == NULL)
        {
-         /* This stub was actually built for a static symbol defined
-            in the same file.  We assume that all static symbols in
-            mips16 code are themselves mips16, so we can simply
-            discard this stub.  Since this function is called before
-            the linker maps input sections to output sections, we can
-            easily discard it by setting the SEC_EXCLUDE flag.  */
-         sec->flags |= SEC_EXCLUDE;
-         return TRUE;
-       }
+         asection *o;
 
-      h = ((struct mips_elf_link_hash_entry *)
-          sym_hashes[r_symndx - extsymoff]);
+         /* This stub is for a local symbol.  This stub will only be
+             needed if there is some relocation (R_MIPS16_26) in this BFD
+             that refers to this symbol.  */
+         for (o = abfd->sections; o != NULL; o = o->next)
+           {
+             Elf_Internal_Rela *sec_relocs;
+             const Elf_Internal_Rela *r, *rend;
 
-      /* H is the symbol this stub is for.  */
+             /* We can ignore stub sections when looking for relocs.  */
+             if ((o->flags & SEC_RELOC) == 0
+                 || o->reloc_count == 0
+                 || mips16_stub_section_p (abfd, o))
+               continue;
 
-      if (CONST_STRNEQ (name, CALL_FP_STUB))
-       loc = &h->call_fp_stub;
-      else
-       loc = &h->call_stub;
-
-      /* If we already have an appropriate stub for this function, we
-        don't need another one, so we can discard this one.  Since
-        this function is called before the linker maps input sections
-        to output sections, we can easily discard it by setting the
-        SEC_EXCLUDE flag.  We can also discard this section if we
-        happen to already know that this is a mips16 function; it is
-        not necessary to check this here, as it is checked later, but
-        it is slightly faster to check now.  */
-      if (*loc != NULL || h->root.other == STO_MIPS16)
-       {
-         sec->flags |= SEC_EXCLUDE;
-         return TRUE;
+             sec_relocs
+               = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+                                            info->keep_memory);
+             if (sec_relocs == NULL)
+               return FALSE;
+
+             rend = sec_relocs + o->reloc_count;
+             for (r = sec_relocs; r < rend; r++)
+               if (ELF_R_SYM (abfd, r->r_info) == r_symndx
+                   && ELF_R_TYPE (abfd, r->r_info) == R_MIPS16_26)
+                   break;
+
+             if (elf_section_data (o)->relocs != sec_relocs)
+               free (sec_relocs);
+
+             if (r < rend)
+               break;
+           }
+
+         if (o == NULL)
+           {
+             /* There is no non-call reloc for this stub, so we do
+                 not need it.  Since this function is called before
+                 the linker maps input sections to output sections, we
+                 can easily discard it by setting the SEC_EXCLUDE
+                 flag.  */
+             sec->flags |= SEC_EXCLUDE;
+             return TRUE;
+           }
+
+         /* Record this stub in an array of local symbol call_stubs for
+             this BFD.  */
+         if (elf_tdata (abfd)->local_call_stubs == NULL)
+           {
+             unsigned long symcount;
+             asection **n;
+             bfd_size_type amt;
+
+             if (elf_bad_symtab (abfd))
+               symcount = NUM_SHDR_ENTRIES (symtab_hdr);
+             else
+               symcount = symtab_hdr->sh_info;
+             amt = symcount * sizeof (asection *);
+             n = bfd_zalloc (abfd, amt);
+             if (n == NULL)
+               return FALSE;
+             elf_tdata (abfd)->local_call_stubs = n;
+           }
+
+         sec->flags |= SEC_KEEP;
+         elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
+
+         /* We don't need to set mips16_stubs_seen in this case.
+             That flag is used to see whether we need to look through
+             the global symbol table for stubs.  We don't need to set
+             it here, because we just have a local stub.  */
        }
+      else
+       {
+         h = ((struct mips_elf_link_hash_entry *)
+              sym_hashes[r_symndx - extsymoff]);
+         
+         /* H is the symbol this stub is for.  */
+         
+         if (CALL_FP_STUB_P (name))
+           loc = &h->call_fp_stub;
+         else
+           loc = &h->call_stub;
+         
+         /* If we already have an appropriate stub for this function, we
+            don't need another one, so we can discard this one.  Since
+            this function is called before the linker maps input sections
+            to output sections, we can easily discard it by setting the
+            SEC_EXCLUDE flag.  */
+         if (*loc != NULL)
+           {
+             sec->flags |= SEC_EXCLUDE;
+             return TRUE;
+           }
 
-      *loc = sec;
-      mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
+         sec->flags |= SEC_KEEP;
+         *loc = sec;
+         mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
+       }
     }
 
   if (dynobj == NULL)
@@ -6656,9 +6744,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          References from a stub section do not count.  */
       if (h != NULL
          && r_type != R_MIPS16_26
-         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), FN_STUB)
-         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), CALL_STUB)
-         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), CALL_FP_STUB))
+         && !mips16_stub_section_p (abfd, sec))
        {
          struct mips_elf_link_hash_entry *mh;
 
@@ -9672,8 +9758,9 @@ _bfd_mips_elf_ignore_discarded_relocs (asection *sec)
 }
 
 bfd_boolean
-_bfd_mips_elf_write_section (bfd *output_bfd, asection *sec,
-                            bfd_byte *contents)
+_bfd_mips_elf_write_section (bfd *output_bfd,
+                            struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
+                             asection *sec, bfd_byte *contents)
 {
   bfd_byte *to, *from, *end;
   int i;
@@ -11105,37 +11192,52 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
     fprintf (file, _(" [no abi set]"));
 
   if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1)
-    fprintf (file, _(" [mips1]"));
+    fprintf (file, " [mips1]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2)
-    fprintf (file, _(" [mips2]"));
+    fprintf (file, " [mips2]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_3)
-    fprintf (file, _(" [mips3]"));
+    fprintf (file, " [mips3]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4)
-    fprintf (file, _(" [mips4]"));
+    fprintf (file, " [mips4]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_5)
-    fprintf (file, _(" [mips5]"));
+    fprintf (file, " [mips5]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32)
-    fprintf (file, _(" [mips32]"));
+    fprintf (file, " [mips32]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64)
-    fprintf (file, _(" [mips64]"));
+    fprintf (file, " [mips64]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2)
-    fprintf (file, _(" [mips32r2]"));
+    fprintf (file, " [mips32r2]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2)
-    fprintf (file, _(" [mips64r2]"));
+    fprintf (file, " [mips64r2]");
   else
     fprintf (file, _(" [unknown ISA]"));
 
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX)
-    fprintf (file, _(" [mdmx]"));
+    fprintf (file, " [mdmx]");
 
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
-    fprintf (file, _(" [mips16]"));
+    fprintf (file, " [mips16]");
 
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
-    fprintf (file, _(" [32bitmode]"));
+    fprintf (file, " [32bitmode]");
   else
     fprintf (file, _(" [not 32bitmode]"));
 
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_NOREORDER)
+    fprintf (file, " [noreorder]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_PIC)
+    fprintf (file, " [PIC]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_CPIC)
+    fprintf (file, " [CPIC]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_XGOT)
+    fprintf (file, " [XGOT]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_UCODE)
+    fprintf (file, " [UCODE]");
+
   fputc ('\n', file);
 
   return TRUE;