Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index ce645817bb257b7d26b9b17cbf4ff78f86921faa..dfb36014066e84915c553909249bd4770f47aa0c 100644 (file)
@@ -455,6 +455,12 @@ struct mips_elf_link_hash_table
   /* True if we already reported the small-data section overflow.  */
   bfd_boolean small_data_overflow_reported;
 
+  /* True if we use the special `__gnu_absolute_zero' symbol.  */
+  bfd_boolean use_absolute_zero;
+
+  /* True if we have been configured for a GNU target.  */
+  bfd_boolean gnu_target;
+
   /* Shortcuts to some dynamic sections, or NULL if they are not
      being used.  */
   asection *srelplt2;
@@ -2903,12 +2909,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
              h->esym.asym.value =
                mips_elf_hash_table (einfo->info)->procedure_count;
            }
-         else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
-           {
-             h->esym.asym.sc = scAbs;
-             h->esym.asym.st = stLabel;
-             h->esym.asym.value = elf_gp (einfo->abfd);
-           }
          else
            h->esym.asym.sc = scUndefined;
        }
@@ -3257,11 +3257,13 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
   bfd_boolean need_relocs = FALSE;
   bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
 
-  if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
-      && (!bfd_link_pic (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
+  if (h != NULL
+      && h->dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
     indx = h->dynindx;
 
-  if ((bfd_link_pic (info) || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
@@ -3279,7 +3281,7 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
       return 1;
 
     case GOT_TLS_LDM:
-      return bfd_link_pic (info) ? 1 : 0;
+      return bfd_link_dll (info) ? 1 : 0;
 
     default:
       return 0;
@@ -3346,6 +3348,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
                               struct mips_elf_link_hash_entry *h,
                               bfd_vma value)
 {
+  bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
   struct mips_elf_link_hash_table *htab;
   int indx;
   asection *sreloc, *sgot;
@@ -3359,21 +3362,16 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
   sgot = htab->root.sgot;
 
   indx = 0;
-  if (h != NULL)
-    {
-      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
-
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
-                                          &h->root)
-         && (!bfd_link_pic (info)
-             || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
-       indx = h->root.dynindx;
-    }
+  if (h != NULL
+      && h->root.dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->root)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+    indx = h->root.dynindx;
 
   if (entry->tls_initialized)
     return;
 
-  if ((bfd_link_pic (info) || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
@@ -3448,7 +3446,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
                         sgot->contents + got_offset
                         + MIPS_ELF_GOT_SIZE (abfd));
 
-      if (!bfd_link_pic (info))
+      if (!bfd_link_dll (info))
        MIPS_ELF_PUT_WORD (abfd, 1,
                           sgot->contents + got_offset);
       else
@@ -3819,6 +3817,7 @@ count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
       for (p = output_bfd->sections; p ; p = p->next)
        if ((p->flags & SEC_EXCLUDE) == 0
            && (p->flags & SEC_ALLOC) != 0
+           && elf_hash_table (info)->dynamic_relocs
            && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
          ++count;
     }
@@ -3984,7 +3983,7 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
        {
        case STV_INTERNAL:
        case STV_HIDDEN:
-         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+         _bfd_mips_elf_hide_symbol (info, h, TRUE);
          break;
        }
       if (!bfd_elf_link_record_dynamic_symbol (info, h))
@@ -4441,6 +4440,12 @@ mips_use_local_got_p (struct bfd_link_info *info,
   if (h->root.dynindx == -1)
     return TRUE;
 
+  /* Absolute symbols, if ever they need a GOT entry, cannot ever go
+     to the local GOT, as they would be implicitly relocated by the
+     base address by the dynamic loader.  */
+  if (bfd_is_abs_symbol (&h->root.root))
+    return FALSE;
+
   /* Symbols that bind locally can (and in the case of forced-local
      symbols, must) live in the local GOT.  */
   if (h->got_only_for_calls
@@ -5241,6 +5246,85 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
     }
 }
 \f
+/* Obtain the field relocated by RELOCATION.  */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+                         const Elf_Internal_Rela *relocation,
+                         bfd *input_bfd, bfd_byte *contents)
+{
+  bfd_vma x = 0;
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Obtain the bytes.  */
+  if (size != 0)
+    x = bfd_get (8 * size, input_bfd, location);
+
+  return x;
+}
+
+/* Store the field relocated by RELOCATION.  */
+
+static void
+mips_elf_store_contents (reloc_howto_type *howto,
+                        const Elf_Internal_Rela *relocation,
+                        bfd *input_bfd, bfd_byte *contents, bfd_vma x)
+{
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Put the value into the output.  */
+  if (size != 0)
+    bfd_put (8 * size, input_bfd, x, location);
+}
+
+/* Try to patch a load from GOT instruction in CONTENTS pointed to by
+   RELOCATION described by HOWTO, with a move of 0 to the load target
+   register, returning TRUE if that is successful and FALSE otherwise.
+   If DOIT is FALSE, then only determine it patching is possible and
+   return status without actually changing CONTENTS.
+*/
+
+static bfd_boolean
+mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
+                          const Elf_Internal_Rela *relocation,
+                          reloc_howto_type *howto, bfd_boolean doit)
+{
+  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+  bfd_byte *location = contents + relocation->r_offset;
+  bfd_boolean nullified = TRUE;
+  bfd_vma x;
+
+  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+
+  /* Obtain the current value.  */
+  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
+
+  /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
+     while RY is at bits [18:16] of the combined 32-bit instruction word.  */
+  if (mips16_reloc_p (r_type)
+      && (((x >> 22) & 0x3ff) == 0x3d3                         /* LW */
+         || ((x >> 22) & 0x3ff) == 0x3c7))                     /* LD */
+    x = (0x3cd << 22) | (x & (7 << 16)) << 3;                  /* LI */
+  else if (micromips_reloc_p (r_type)
+          && ((x >> 26) & 0x37) == 0x37)                       /* LW/LD */
+    x = (0xc << 26) | (x & (0x1f << 21));                      /* ADDIU */
+  else if (((x >> 26) & 0x3f) == 0x23                          /* LW */
+          || ((x >> 26) & 0x3f) == 0x37)                       /* LD */
+    x = (0x9 << 26) | (x & (0x1f << 16));                      /* ADDIU */
+  else
+    nullified = FALSE;
+
+  /* Put the value into the output.  */
+  if (doit && nullified)
+    mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+
+  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, FALSE, location);
+
+  return nullified;
+}
+
 /* Calculate the value produced by the RELOCATION (which comes from
    the INPUT_BFD).  The ADDEND is the addend to use for this
    RELOCATION; RELOCATION->R_ADDEND is ignored.
@@ -5256,7 +5340,7 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
 
 static bfd_reloc_status_type
 mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
-                              asection *input_section,
+                              asection *input_section, bfd_byte *contents,
                               struct bfd_link_info *info,
                               const Elf_Internal_Rela *relocation,
                               bfd_vma addend, reloc_howto_type *howto,
@@ -5652,6 +5736,48 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
                                && (target_is_16_bit_code_p
                                    || target_is_micromips_code_p))));
 
+  resolved_to_zero = (h != NULL
+                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
+
+  switch (r_type)
+    {
+    case R_MIPS16_CALL16:
+    case R_MIPS16_GOT16:
+    case R_MIPS_CALL16:
+    case R_MIPS_GOT16:
+    case R_MIPS_GOT_PAGE:
+    case R_MIPS_GOT_DISP:
+    case R_MIPS_GOT_LO16:
+    case R_MIPS_CALL_LO16:
+    case R_MICROMIPS_CALL16:
+    case R_MICROMIPS_GOT16:
+    case R_MICROMIPS_GOT_PAGE:
+    case R_MICROMIPS_GOT_DISP:
+    case R_MICROMIPS_GOT_LO16:
+    case R_MICROMIPS_CALL_LO16:
+      if (resolved_to_zero
+         && !bfd_link_relocatable (info)
+         && mips_elf_nullify_got_load (input_bfd, contents,
+                                       relocation, howto, TRUE))
+       return bfd_reloc_continue;
+
+      /* Fall through.  */
+    case R_MIPS_GOT_HI16:
+    case R_MIPS_CALL_HI16:
+    case R_MICROMIPS_GOT_HI16:
+    case R_MICROMIPS_CALL_HI16:
+      if (resolved_to_zero
+         && htab->use_absolute_zero
+         && bfd_link_pic (info))
+       {
+         /* Redirect to the special `__gnu_absolute_zero' symbol.  */
+         h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
+                                        FALSE, FALSE, FALSE);
+         BFD_ASSERT (h != NULL);
+       }
+      break;
+    }
+
   local_p = (h == NULL || mips_use_local_got_p (info, h));
 
   gp0 = _bfd_get_gp_value (input_bfd);
@@ -5672,10 +5798,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       addend = 0;
     }
 
-  resolved_to_zero = (h != NULL
-                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info,
-                                                         &h->root));
-
   /* If we haven't already determined the GOT offset, and we're going
      to need it, get it now.  */
   switch (r_type)
@@ -6315,24 +6437,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
 }
 
-/* Obtain the field relocated by RELOCATION.  */
-
-static bfd_vma
-mips_elf_obtain_contents (reloc_howto_type *howto,
-                         const Elf_Internal_Rela *relocation,
-                         bfd *input_bfd, bfd_byte *contents)
-{
-  bfd_vma x = 0;
-  bfd_byte *location = contents + relocation->r_offset;
-  unsigned int size = bfd_get_reloc_size (howto);
-
-  /* Obtain the bytes.  */
-  if (size != 0)
-    x = bfd_get (8 * size, input_bfd, location);
-
-  return x;
-}
-
 /* It has been determined that the result of the RELOCATION is the
    VALUE.  Use HOWTO to place VALUE into the output file at the
    appropriate position.  The SECTION is the section to which the
@@ -6353,7 +6457,6 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   bfd_vma x;
   bfd_byte *location;
   int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
-  unsigned int size;
 
   /* Figure out where the relocation is occurring.  */
   location = contents + relocation->r_offset;
@@ -6512,9 +6615,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
     }
 
   /* Put the value into the output.  */
-  size = bfd_get_reloc_size (howto);
-  if (size != 0)
-    bfd_put (8 * size, input_bfd, x, location);
+  mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
 
   _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
                               location);
@@ -6794,8 +6895,14 @@ _bfd_elf_mips_mach (flagword flags)
     case E_MIPS_MACH_LS2F:
       return bfd_mach_mips_loongson_2f;
 
-    case E_MIPS_MACH_LS3A:
-      return bfd_mach_mips_loongson_3a;
+    case E_MIPS_MACH_GS464:
+      return bfd_mach_mips_gs464;
+
+    case E_MIPS_MACH_GS464E:
+      return bfd_mach_mips_gs464e;
+
+    case E_MIPS_MACH_GS264E:
+      return bfd_mach_mips_gs264e;
 
     case E_MIPS_MACH_OCTEON3:
       return bfd_mach_mips_octeon3;
@@ -7849,6 +7956,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
            return FALSE;
 
          h = (struct elf_link_hash_entry *) bh;
+         h->mark = 1;
          h->non_elf = 0;
          h->def_regular = 1;
          h->type = STT_SECTION;
@@ -8097,6 +8205,47 @@ mips_elf_make_plt_record (bfd *abfd)
   return entry;
 }
 
+/* Define the special `__gnu_absolute_zero' symbol.  We only need this
+   for PIC code, as otherwise there is no load-time relocation involved
+   and local GOT entries whose value is zero at static link time will
+   retain their value at load time.  */
+
+static bfd_boolean
+mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
+                              struct mips_elf_link_hash_table *htab,
+                              unsigned int r_type)
+{
+  union
+    {
+      struct elf_link_hash_entry *eh;
+      struct bfd_link_hash_entry *bh;
+    }
+  hzero;
+
+  BFD_ASSERT (!htab->use_absolute_zero);
+  BFD_ASSERT (bfd_link_pic (info));
+
+  hzero.bh = NULL;
+  if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
+                                        BSF_GLOBAL, bfd_abs_section_ptr, 0,
+                                        NULL, FALSE, FALSE, &hzero.bh))
+    return FALSE;
+
+  BFD_ASSERT (hzero.bh != NULL);
+  hzero.eh->size = 0;
+  hzero.eh->type = STT_NOTYPE;
+  hzero.eh->other = STV_PROTECTED;
+  hzero.eh->def_regular = 1;
+  hzero.eh->non_elf = 0;
+
+  if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, TRUE, r_type))
+    return FALSE;
+
+  htab->use_absolute_zero = TRUE;
+
+  return TRUE;
+}
+
 /* Look through the relocs for a section during the first phase, and
    allocate space in the global offset table and record the need for
    standard MIPS and compressed procedure linkage table entries.  */
@@ -8449,24 +8598,52 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_MIPS_GOT16:
-       case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_PAGE:
-       case R_MIPS_GOT_OFST:
        case R_MIPS_GOT_DISP:
+       case R_MIPS16_GOT16:
+       case R_MICROMIPS_GOT16:
+       case R_MICROMIPS_GOT_LO16:
+       case R_MICROMIPS_GOT_PAGE:
+       case R_MICROMIPS_GOT_DISP:
+         /* If we have a symbol that will resolve to zero at static link
+            time and it is used by a GOT relocation applied to code we
+            cannot relax to an immediate zero load, then we will be using
+            the special `__gnu_absolute_zero' symbol whose value is zero
+            at dynamic load time.  We ignore HI16-type GOT relocations at
+            this stage, because their handling will depend entirely on
+            the corresponding LO16-type GOT relocation.  */
+         if (!call_hi16_reloc_p (r_type)
+             && h != NULL
+             && bfd_link_pic (info)
+             && !htab->use_absolute_zero
+             && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+           {
+             bfd_boolean rel_reloc;
+
+             if (!mips_elf_get_section_contents (abfd, sec, &contents))
+               return FALSE;
+
+             rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
+             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
+
+             if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+                                             FALSE))
+               if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
+                 return FALSE;
+           }
+
+         /* Fall through.  */
+       case R_MIPS_GOT_HI16:
+       case R_MIPS_GOT_OFST:
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_LDM:
-       case R_MIPS16_GOT16:
        case R_MIPS16_TLS_GOTTPREL:
        case R_MIPS16_TLS_GD:
        case R_MIPS16_TLS_LDM:
-       case R_MICROMIPS_GOT16:
        case R_MICROMIPS_GOT_HI16:
-       case R_MICROMIPS_GOT_LO16:
-       case R_MICROMIPS_GOT_PAGE:
        case R_MICROMIPS_GOT_OFST:
-       case R_MICROMIPS_GOT_DISP:
        case R_MICROMIPS_TLS_GOTTPREL:
        case R_MICROMIPS_TLS_GD:
        case R_MICROMIPS_TLS_LDM:
@@ -8956,10 +9133,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
       if (h->root.type == bfd_link_hash_undefweak)
        {
-         /* Do not copy relocations for undefined weak symbols with
-            non-default visibility.  */
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-             || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+         /* Do not copy relocations for undefined weak symbols that
+            we are not going to export.  */
+         if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            do_copy = FALSE;
 
          /* Make sure undefined weak symbols are output as a dynamic
@@ -9048,7 +9224,8 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         the symbol to the stub location.  This is required to make
         function pointers compare as equal between the normal
         executable and the shared library.  */
-      if (!h->def_regular)
+      if (!h->def_regular
+         && !bfd_is_abs_section (htab->sstubs->output_section))
        {
          hmips->needs_lazy_stub = TRUE;
          htab->lazy_stub_count++;
@@ -9896,7 +10073,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
        }
       else
        {
-         if (sreldyn && sreldyn->size > 0)
+         if (sreldyn && sreldyn->size > 0
+             && !bfd_is_abs_section (sreldyn->output_section))
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
                return FALSE;
@@ -10267,10 +10445,10 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
       /* Figure out what value we are supposed to relocate.  */
       switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
-                                            input_section, info, rel,
-                                            addend, howto, local_syms,
-                                            local_sections, &value,
-                                            &name, &cross_mode_jump_p,
+                                            input_section, contents,
+                                            info, rel, addend, howto,
+                                            local_syms, local_sections,
+                                            &value, &name, &cross_mode_jump_p,
                                             use_saved_addend_p))
        {
        case bfd_reloc_continue:
@@ -10607,8 +10785,25 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
       got_address_low = got_address & 0xffff;
 
+      /* The PLT sequence is not safe for N64 if .got.plt entry's address
+        cannot be loaded in two instructions.  */
+      if (ABI_64_P (output_bfd)
+         && ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
+              "supported; consider using `-Ttext-segment=...'"),
+            output_bfd,
+            htab->root.sgotplt->output_section,
+            (int64_t) got_address);
+         bfd_set_error (bfd_error_no_error);
+         return FALSE;
+       }
+
       /* Initially point the .got.plt entry at the PLT header.  */
-      loc = (htab->root.sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+      loc = (htab->root.sgotplt->contents
+            + got_index * MIPS_ELF_GOT_SIZE (dynobj));
       if (ABI_64_P (output_bfd))
        bfd_put_64 (output_bfd, header_address, loc);
       else
@@ -10976,12 +11171,6 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
       sym->st_value = 1;
     }
-  else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
-    {
-      sym->st_shndx = SHN_ABS;
-      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
-      sym->st_value = elf_gp (output_bfd);
-    }
   else if (SGI_COMPAT (output_bfd))
     {
       if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
@@ -11256,8 +11445,19 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 
   /* The PLT sequence is not safe for N64 if .got.plt's address can
      not be loaded in two instructions.  */
-  BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
-             || ~(gotplt_value | 0x7fffffff) == 0);
+  if (ABI_64_P (output_bfd)
+      && ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+    {
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
+          "supported; consider using `-Ttext-segment=...'"),
+        output_bfd,
+        htab->root.sgotplt->output_section,
+        (int64_t) gotplt_value);
+      bfd_set_error (bfd_error_no_error);
+      return FALSE;
+    }
 
   /* Install the PLT header.  */
   loc = htab->root.splt->contents;
@@ -11782,6 +11982,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                   : sizeof (Elf32_External_Rel)));
              /* Adjust the section size too.  Tools like the prelinker
                 can reasonably expect the values to the same.  */
+             BFD_ASSERT (!bfd_is_abs_section (s->output_section));
              elf_section_data (s->output_section)->this_hdr.sh_size
                = dyn.d_un.d_val;
              break;
@@ -11966,8 +12167,16 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
       break;
 
-    case bfd_mach_mips_loongson_3a:
-      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_LS3A;
+    case bfd_mach_mips_gs464:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464;
+      break;
+
+    case bfd_mach_mips_gs464e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464E;
+      break;
+
+    case bfd_mach_mips_gs264e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS264E;
       break;
 
     case bfd_mach_mips_octeon:
@@ -12545,6 +12754,27 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
   if (indmips->has_nonpic_branches)
     dirmips->has_nonpic_branches = TRUE;
 }
+
+/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
+   to hide it.  It has to remain global (it will also be protected) so as to
+   be assigned a global GOT entry, which will then remain unchanged at load
+   time.  */
+
+void
+_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
+                          struct elf_link_hash_entry *entry,
+                          bfd_boolean force_local)
+{
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+  if (htab->use_absolute_zero
+      && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
+    return;
+
+  _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
+}
 \f
 #define PDR_SIZE 32
 
@@ -13947,14 +14177,17 @@ _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
 
 /* A function that the linker calls to select between all or only
    32-bit microMIPS instructions, and between making or ignoring
-   branch relocation checks for invalid transitions between ISA modes.  */
+   branch relocation checks for invalid transitions between ISA modes.
+   Also record whether we have been configured for a GNU target.  */
 
 void
 _bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
-                           bfd_boolean ignore_branch_isa)
+                           bfd_boolean ignore_branch_isa,
+                           bfd_boolean gnu_target)
 {
   mips_elf_hash_table (info)->insn32 = insn32;
   mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+  mips_elf_hash_table (info)->gnu_target = gnu_target;
 }
 \f
 /* Structure for saying that BFD machine EXTENSION extends BASE.  */
@@ -13975,7 +14208,9 @@ static const struct mips_mach_extension mips_mach_extensions[] =
   { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
   { bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
   { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
-  { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64r2 },
+  { bfd_mach_mips_gs264e, bfd_mach_mips_gs464e },
+  { bfd_mach_mips_gs464e, bfd_mach_mips_gs464 },
+  { bfd_mach_mips_gs464, bfd_mach_mipsisa64r2 },
 
   /* MIPS64 extensions.  */
   { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
@@ -14087,7 +14322,6 @@ bfd_mips_isa_ext_mach (unsigned int isa_ext)
     case AFL_EXT_10000:              return bfd_mach_mips10000;
     case AFL_EXT_LOONGSON_2E: return bfd_mach_mips_loongson_2e;
     case AFL_EXT_LOONGSON_2F: return bfd_mach_mips_loongson_2f;
-    case AFL_EXT_LOONGSON_3A: return bfd_mach_mips_loongson_3a;
     case AFL_EXT_SB1:        return bfd_mach_mips_sb1;
     case AFL_EXT_OCTEON:      return bfd_mach_mips_octeon;
     case AFL_EXT_OCTEONP:     return bfd_mach_mips_octeonp;
@@ -14116,7 +14350,6 @@ bfd_mips_isa_ext (bfd *abfd)
     case bfd_mach_mips10000:       return AFL_EXT_10000;
     case bfd_mach_mips_loongson_2e: return AFL_EXT_LOONGSON_2E;
     case bfd_mach_mips_loongson_2f: return AFL_EXT_LOONGSON_2F;
-    case bfd_mach_mips_loongson_3a: return AFL_EXT_LOONGSON_3A;
     case bfd_mach_mips_sb1:        return AFL_EXT_SB1;
     case bfd_mach_mips_octeon:     return AFL_EXT_OCTEON;
     case bfd_mach_mips_octeonp:            return AFL_EXT_OCTEONP;
@@ -14232,7 +14465,7 @@ infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags)
       && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
       && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
       && abiflags->isa_level >= 32
-      && abiflags->isa_ext != AFL_EXT_LOONGSON_3A)
+      && abiflags->ases != AFL_ASE_LOONGSON_EXT)
     abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
 }
 
@@ -15653,6 +15886,18 @@ print_mips_ases (FILE *file, unsigned int mask)
     fputs ("\n\tXPA ASE", file);
   if (mask & AFL_ASE_MIPS16E2)
     fputs ("\n\tMIPS16e2 ASE", file);
+  if (mask & AFL_ASE_CRC)
+    fputs ("\n\tCRC ASE", file);
+  if (mask & AFL_ASE_GINV)
+    fputs ("\n\tGINV ASE", file);
+  if (mask & AFL_ASE_LOONGSON_MMI)
+    fputs ("\n\tLoongson MMI ASE", file);
+  if (mask & AFL_ASE_LOONGSON_CAM)
+    fputs ("\n\tLoongson CAM ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT)
+    fputs ("\n\tLoongson EXT ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT2)
+    fputs ("\n\tLoongson EXT2 ASE", file);
   if (mask == 0)
     fprintf (file, "\n\t%s", _("None"));
   else if ((mask & ~AFL_ASE_MASK) != 0)
@@ -15679,9 +15924,6 @@ print_mips_isa_ext (FILE *file, unsigned int isa_ext)
     case AFL_EXT_OCTEONP:
       fputs ("Cavium Networks OcteonP", file);
       break;
-    case AFL_EXT_LOONGSON_3A:
-      fputs ("Loongson 3A", file);
-      break;
     case AFL_EXT_OCTEON:
       fputs ("Cavium Networks Octeon", file);
       break;
@@ -16209,10 +16451,23 @@ bfd_mips_elf_get_abiflags (bfd *abfd)
   return tdata->abiflags_valid ? &tdata->abiflags : NULL;
 }
 
+/* MIPS libc ABI versions, used with the EI_ABIVERSION ELF file header
+   field.  Taken from `libc-abis.h' generated at GNU libc build time.
+   Using a MIPS_ prefix as other libc targets use different values.  */
+enum
+{
+  MIPS_LIBC_ABI_DEFAULT = 0,
+  MIPS_LIBC_ABI_MIPS_PLT,
+  MIPS_LIBC_ABI_UNIQUE,
+  MIPS_LIBC_ABI_MIPS_O32_FP64,
+  MIPS_LIBC_ABI_ABSOLUTE,
+  MIPS_LIBC_ABI_MAX
+};
+
 void
 _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
 {
-  struct mips_elf_link_hash_table *htab;
+  struct mips_elf_link_hash_table *htab = NULL;
   Elf_Internal_Ehdr *i_ehdrp;
 
   i_ehdrp = elf_elfheader (abfd);
@@ -16220,20 +16475,25 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
     {
       htab = mips_elf_hash_table (link_info);
       BFD_ASSERT (htab != NULL);
-
-      if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
-       i_ehdrp->e_ident[EI_ABIVERSION] = 1;
     }
 
-  _bfd_elf_post_process_headers (abfd, link_info);
+  if (htab != NULL && htab->use_plts_and_copy_relocs && !htab->is_vxworks)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
 
   if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
       || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
-    i_ehdrp->e_ident[EI_ABIVERSION] = 3;
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+
+  /* Mark that we need support for absolute symbols in the dynamic loader.  */
+  if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
+
+  _bfd_elf_post_process_headers (abfd, link_info);
 }
 
 int
-_bfd_mips_elf_compact_eh_encoding (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_compact_eh_encoding
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
 {
   return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
 }
@@ -16241,7 +16501,8 @@ _bfd_mips_elf_compact_eh_encoding (struct bfd_link_info *link_info ATTRIBUTE_UNU
 /* Return the opcode for can't unwind.  */
 
 int
-_bfd_mips_elf_cant_unwind_opcode (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_cant_unwind_opcode
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
 {
   return COMPACT_EH_CANT_UNWIND_OPCODE;
 }
This page took 0.038582 seconds and 4 git commands to generate.