gas: blackfin: add tests for recent loop label fixes
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index 804a7d4a4e8832bcb6b88ddcafbcaa09fa256b40..8feb5c483794d022a43631e75c1aa740483ae502 100644 (file)
@@ -374,6 +374,11 @@ struct mips_elf_link_hash_entry
   /* The highest GGA_* value that satisfies all references to this symbol.  */
   unsigned int global_got_area : 2;
 
+  /* True if all GOT relocations against this symbol are for calls.  This is
+     a looser condition than no_fn_stub below, because there may be other
+     non-call non-GOT relocations against the symbol.  */
+  unsigned int got_only_for_calls : 1;
+
   /* True if one of the relocations described by possibly_dynamic_relocs
      is against a readonly section.  */
   unsigned int readonly_reloc : 1;
@@ -778,23 +783,6 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                     \
   (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
 
-/* Determine whether the internal relocation of index REL_IDX is REL
-   (zero) or RELA (non-zero).  The assumption is that, if there are
-   two relocation sections for this section, one of them is REL and
-   the other is RELA.  If the index of the relocation we're testing is
-   in range for the first relocation section, check that the external
-   relocation size is that for RELA.  It is also assumed that, if
-   rel_idx is not in range for the first section, and this first
-   section contains REL relocs, then the relocation is in the second
-   section, that is RELA.  */
-#define MIPS_RELOC_RELA_P(abfd, sec, rel_idx)                          \
-  ((NUM_SHDR_ENTRIES (&elf_section_data (sec)->rel_hdr)                        \
-    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel             \
-    > (bfd_vma)(rel_idx))                                              \
-   == (elf_section_data (sec)->rel_hdr.sh_entsize                      \
-       == (ABI_64_P (abfd) ? sizeof (Elf64_External_Rela)              \
-          : sizeof (Elf32_External_Rela))))
-
 /* The name of the dynamic relocation section.  */
 #define MIPS_ELF_REL_DYN_NAME(INFO) \
   (mips_elf_hash_table (INFO)->is_vxworks ? ".rela.dyn" : ".rel.dyn")
@@ -1073,6 +1061,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->call_fp_stub = NULL;
       ret->tls_type = GOT_NORMAL;
       ret->global_got_area = GGA_NONE;
+      ret->got_only_for_calls = TRUE;
       ret->readonly_reloc = FALSE;
       ret->has_static_relocs = FALSE;
       ret->no_fn_stub = FALSE;
@@ -3477,11 +3466,13 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
 
 /* If H is a symbol that needs a global GOT entry, but has a dynamic
    symbol table index lower than any we've seen to date, record it for
-   posterity.  */
+   posterity.  FOR_CALL is true if the caller is only interested in
+   using the GOT entry for calls.  */
 
 static bfd_boolean
 mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
                                   bfd *abfd, struct bfd_link_info *info,
+                                  bfd_boolean for_call,
                                   unsigned char tls_flag)
 {
   struct mips_elf_link_hash_table *htab;
@@ -3493,6 +3484,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
   BFD_ASSERT (htab != NULL);
 
   hmips = (struct mips_elf_link_hash_entry *) h;
+  if (!for_call)
+    hmips->got_only_for_calls = FALSE;
 
   /* A global symbol in the GOT must also be in the dynamic symbol
      table.  */
@@ -3856,10 +3849,12 @@ static int
 mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
 {
   struct bfd_link_info *info;
+  struct mips_elf_link_hash_table *htab;
   struct mips_got_info *g;
 
   info = (struct bfd_link_info *) data;
-  g = mips_elf_hash_table (info)->got_info;
+  htab = mips_elf_hash_table (info);
+  g = htab->got_info;
   if (h->global_got_area != GGA_NONE)
     {
       /* Make a final decision about whether the symbol belongs in the
@@ -3871,7 +3866,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
         Note that the former condition does not always imply the
         latter: symbols do not bind locally if they are completely
         undefined.  We'll report undefined symbols later if appropriate.  */
-      if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root))
+      if (h->root.dynindx == -1
+         || (h->got_only_for_calls
+             ? SYMBOL_CALLS_LOCAL (info, &h->root)
+             : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
        {
          /* The symbol belongs in the local GOT.  We no longer need this
             entry if it was only used for relocations; those relocations
@@ -3880,6 +3878,13 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
            g->local_gotno++;
          h->global_got_area = GGA_NONE;
        }
+      else if (htab->is_vxworks
+              && h->got_only_for_calls
+              && h->root.plt.offset != MINUS_ONE)
+       /* On VxWorks, calls can refer directly to the .got.plt entry;
+          they don't need entries in the regular GOT.  .got.plt entries
+          will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
+       h->global_got_area = GGA_NONE;
       else
        {
          g->global_gotno++;
@@ -5260,7 +5265,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
               && h->root.def_dynamic
               && !h->root.def_regular
               && !h->has_static_relocs))
-         && r_symndx != 0
+         && r_symndx != STN_UNDEF
          && (h == NULL
              || h->root.root.type != bfd_link_hash_undefweak
              || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
@@ -7088,14 +7093,14 @@ mips_elf_rel_relocation_p (bfd *abfd, asection *sec,
   Elf_Internal_Shdr *rel_hdr;
   const struct elf_backend_data *bed;
 
-  /* To determine which flavor or relocation this is, we depend on the
-     fact that the INPUT_SECTION's REL_HDR is read before its REL_HDR2.  */
-  rel_hdr = &elf_section_data (sec)->rel_hdr;
+  /* To determine which flavor of relocation this is, we depend on the
+     fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR.  */
+  rel_hdr = elf_section_data (sec)->rel.hdr;
+  if (rel_hdr == NULL)
+    return FALSE;
   bed = get_elf_backend_data (abfd);
-  if ((size_t) (rel - relocs)
-      >= (NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel))
-    rel_hdr = elf_section_data (sec)->rel_hdr2;
-  return rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (abfd);
+  return ((size_t) (rel - relocs)
+         < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel);
 }
 
 /* Read the addend for REL relocation REL, which belongs to bfd ABFD.
@@ -7654,11 +7659,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_CALL_LO16:
          if (h != NULL)
            {
-             /* VxWorks call relocations point at the function's .got.plt
-                entry, which will be allocated by adjust_dynamic_symbol.
-                Otherwise, this symbol requires a global GOT entry.  */
-             if ((!htab->is_vxworks || h->forced_local)
-                 && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+             /* Make sure there is room in the regular GOT to hold the
+                function's address.  We may eliminate it in favour of
+                a .got.plt entry later; see mips_elf_count_got_symbols.  */
+             if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0))
                return FALSE;
 
              /* We need a stub, not a plt entry for the undefined
@@ -7718,7 +7722,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_MIPS_GOT_DISP:
-         if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+         if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+                                                      FALSE, 0))
            return FALSE;
          break;
 
@@ -7730,7 +7735,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_TLS_LDM:
          if (r_type == R_MIPS_TLS_LDM)
            {
-             r_symndx = 0;
+             r_symndx = STN_UNDEF;
              h = NULL;
            }
          /* Fall through */
@@ -7750,13 +7755,13 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  (struct mips_elf_link_hash_entry *) h;
                hmips->tls_type |= flag;
 
-               if (h && !mips_elf_record_global_got_symbol (h, abfd,
-                                                            info, flag))
+               if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+                                                            FALSE, flag))
                  return FALSE;
              }
            else
              {
-               BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
+               BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF);
 
                if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
                                                       rel->r_addend,
@@ -7896,7 +7901,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_MIPS_HIGHEST:
              /* Don't refuse a high part relocation if it's against
                 no symbol (e.g. part of a compound relocation).  */
-             if (r_symndx == 0)
+             if (r_symndx == STN_UNDEF)
                break;
 
              /* R_MIPS_HI16 against _gp_disp is used for $gp setup,
@@ -8154,8 +8159,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             VxWorks does not enforce the same mapping between the GOT
             and the symbol table, so the same requirement does not
             apply there.  */
-         if (!htab->is_vxworks && hmips->global_got_area > GGA_RELOC_ONLY)
-           hmips->global_got_area = GGA_RELOC_ONLY;
+         if (!htab->is_vxworks)
+           {
+             if (hmips->global_got_area > GGA_RELOC_ONLY)
+               hmips->global_got_area = GGA_RELOC_ONLY;
+             hmips->got_only_for_calls = FALSE;
+           }
 
          mips_elf_allocate_dynamic_relocations
            (dynobj, info, hmips->possibly_dynamic_relocs);
@@ -8957,13 +8966,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       asection *sec;
       Elf_Internal_Shdr *symtab_hdr;
       struct elf_link_hash_entry *h;
+      bfd_boolean rel_reloc;
 
+      rel_reloc = (NEWABI_P (input_bfd)
+                  && mips_elf_rel_relocation_p (input_bfd, input_section,
+                                                relocs, rel));
       /* Find the relocation howto for this relocation.  */
-      howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type,
-                                      NEWABI_P (input_bfd)
-                                      && (MIPS_RELOC_RELA_P
-                                          (input_bfd, input_section,
-                                           rel - relocs)));
+      howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
 
       r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
This page took 0.026911 seconds and 4 git commands to generate.