2000-07-09 Koundinya K <kk@ddeorg.soft.net>
[deliverable/binutils-gdb.git] / bfd / elf32-mips.c
index 2fd04cc9f4b27a67325eafa27c996d71df1c1e5e..a0512acc1589a4116a543f6ee5d7e77cf4bdf6f2 100644 (file)
@@ -108,8 +108,10 @@ static void bfd_mips_elf32_swap_gptab_in
   PARAMS ((bfd *, const Elf32_External_gptab *, Elf32_gptab *));
 static void bfd_mips_elf32_swap_gptab_out
   PARAMS ((bfd *, const Elf32_gptab *, Elf32_External_gptab *));
+#if 0
 static void bfd_mips_elf_swap_msym_in 
   PARAMS ((bfd *, const Elf32_External_Msym *, Elf32_Internal_Msym *));
+#endif
 static void bfd_mips_elf_swap_msym_out
   PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
 static boolean mips_elf_sym_is_global PARAMS ((bfd *, asymbol *));
@@ -157,8 +159,9 @@ static boolean mips_elf_record_global_got_symbol
           struct mips_got_info *));
 static bfd_vma mips_elf_got_page
   PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *));
-static const Elf_Internal_Rela *mips_elf_next_lo16_relocation
-  PARAMS ((const Elf_Internal_Rela *, const Elf_Internal_Rela *));
+static const Elf_Internal_Rela *mips_elf_next_relocation
+  PARAMS ((unsigned int, const Elf_Internal_Rela *, 
+          const Elf_Internal_Rela *));
 static bfd_reloc_status_type mips_elf_calculate_relocation
   PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
           const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
@@ -179,11 +182,11 @@ static asection * mips_elf_got_section PARAMS ((bfd *));
 static struct mips_got_info *mips_elf_got_info 
   PARAMS ((bfd *, asection **));
 static boolean mips_elf_local_relocation_p
-  PARAMS ((bfd *, const Elf_Internal_Rela *, asection **));
+  PARAMS ((bfd *, const Elf_Internal_Rela *, asection **, boolean));
 static bfd_vma mips_elf_create_local_got_entry 
   PARAMS ((bfd *, struct mips_got_info *, asection *, bfd_vma));
 static bfd_vma mips_elf_got16_entry 
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_vma));
+  PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, boolean));
 static boolean mips_elf_create_dynamic_relocation 
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
           struct mips_elf_link_hash_entry *, asection *,
@@ -192,6 +195,8 @@ static void mips_elf_allocate_dynamic_relocations
   PARAMS ((bfd *, unsigned int));
 static boolean mips_elf_stub_section_p 
   PARAMS ((bfd *, asection *));
+static int sort_dynamic_relocs
+  PARAMS ((const void *, const void *));
 
 /* The level of IRIX compatibility we're striving for.  */
 
@@ -201,6 +206,9 @@ typedef enum {
   ict_irix6
 } irix_compat_t;
 
+/* This will be used when we sort the dynamic relocation records.  */
+static bfd *reldyn_sorting_bfd;
+
 /* Nonzero if ABFD is using the N32 ABI.  */
 
 #define ABI_N32_P(abfd) \
@@ -612,7 +620,7 @@ static reloc_howto_type elf_mips_howto_table[] =
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   /* 16 bit call through global offset table.  */
   HOWTO (R_MIPS_CALL16,                /* type */
@@ -941,6 +949,86 @@ static reloc_howto_type elf_mips16_gprel_howto =
         0x07ff001f,            /* dst_mask */
         false);                /* pcrel_offset */
 
+/* GNU extensions for embedded-pic.  */
+/* High 16 bits of symbol value, pc-relative.  */
+static reloc_howto_type elf_mips_gnu_rel_hi16 =
+  HOWTO (R_MIPS_GNU_REL_HI16,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        _bfd_mips_elf_hi16_reloc,      /* special_function */
+        "R_MIPS_GNU_REL_HI16", /* name */
+        true,                  /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        true);                 /* pcrel_offset */
+
+/* Low 16 bits of symbol value, pc-relative.  */
+static reloc_howto_type elf_mips_gnu_rel_lo16 =
+  HOWTO (R_MIPS_GNU_REL_LO16,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        _bfd_mips_elf_lo16_reloc,      /* special_function */
+        "R_MIPS_GNU_REL_LO16", /* name */
+        true,                  /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        true);                 /* pcrel_offset */
+
+/* 16 bit offset for pc-relative branches.  */
+static reloc_howto_type elf_mips_gnu_rel16_s2 =
+  HOWTO (R_MIPS_GNU_REL16_S2,  /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_GNU_REL16_S2", /* name */
+        true,                  /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        true);                 /* pcrel_offset */
+
+/* 64 bit pc-relative.  */
+static reloc_howto_type elf_mips_gnu_pcrel64 =
+  HOWTO (R_MIPS_PC64,          /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_PC64",         /* name */
+        true,                  /* partial_inplace */
+        MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
+        true);                 /* pcrel_offset */
+
+/* 32 bit pc-relative.  */
+static reloc_howto_type elf_mips_gnu_pcrel32 =
+  HOWTO (R_MIPS_PC32,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MIPS_PC32",         /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true);                 /* pcrel_offset */
 
 /* GNU extension to record C++ vtable hierarchy */
 static reloc_howto_type elf_mips_gnu_vtinherit_howto =
@@ -1436,7 +1524,7 @@ gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
     reloc_entry->address += input_section->output_offset;
 
   /* Make sure it fit in 16 bits.  */
-  if (val >= 0x8000 && val < 0xffff8000)
+  if ((long) val >= 0x8000 || (long) val < -0x8000)
     return bfd_reloc_overflow;
 
   return bfd_reloc_ok;
@@ -1880,6 +1968,16 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
       return &elf_mips_gnu_vtinherit_howto;
     case BFD_RELOC_VTABLE_ENTRY:
       return &elf_mips_gnu_vtentry_howto;
+    case BFD_RELOC_PCREL_HI16_S:
+      return &elf_mips_gnu_rel_hi16;
+    case BFD_RELOC_PCREL_LO16:
+      return &elf_mips_gnu_rel_lo16;
+    case BFD_RELOC_16_PCREL_S2:
+      return &elf_mips_gnu_rel16_s2;
+    case BFD_RELOC_64_PCREL:
+      return &elf_mips_gnu_pcrel64;
+    case BFD_RELOC_32_PCREL:
+      return &elf_mips_gnu_pcrel32;
     }
 }
 
@@ -1903,6 +2001,21 @@ mips_rtype_to_howto (r_type)
     case R_MIPS_GNU_VTENTRY:
       return &elf_mips_gnu_vtentry_howto;
       break;
+    case R_MIPS_GNU_REL_HI16:
+      return &elf_mips_gnu_rel_hi16;
+      break;
+    case R_MIPS_GNU_REL_LO16:
+      return &elf_mips_gnu_rel_lo16;
+      break;
+    case R_MIPS_GNU_REL16_S2:
+      return &elf_mips_gnu_rel16_s2;
+      break;
+    case R_MIPS_PC64:
+      return &elf_mips_gnu_pcrel64;
+      break;
+    case R_MIPS_PC32:
+      return &elf_mips_gnu_pcrel32;
+      break;
 
     default:
       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
@@ -2115,7 +2228,7 @@ bfd_mips_elf_swap_options_out (abfd, in, ex)
   bfd_h_put_16 (abfd, in->section, ex->section);
   bfd_h_put_32 (abfd, in->info, ex->info);
 }
-
+#if 0
 /* Swap in an MSYM entry.  */
 
 static void
@@ -2127,7 +2240,7 @@ bfd_mips_elf_swap_msym_in (abfd, ex, in)
   in->ms_hash_value = bfd_h_get_32 (abfd, ex->ms_hash_value);
   in->ms_info = bfd_h_get_32 (abfd, ex->ms_info);
 }
-
+#endif
 /* Swap out an MSYM entry.  */
 
 static void
@@ -2351,21 +2464,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
   boolean ok;
 
   /* Check if we have the same endianess */
-  if (ibfd->xvec->byteorder != obfd->xvec->byteorder
-      && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
-    {
-      const char *msg;
-
-      if (bfd_big_endian (ibfd))
-       msg = _("%s: compiled for a big endian system and target is little endian");
-      else
-       msg = _("%s: compiled for a little endian system and target is big endian");
-
-      (*_bfd_error_handler) (msg, bfd_get_filename (ibfd));
-
-      bfd_set_error (bfd_error_wrong_format);
-      return false;
-    }
+  if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
+    return false;
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
@@ -3072,18 +3172,6 @@ static asection mips_elf_acom_section;
 static asymbol mips_elf_acom_symbol;
 static asymbol *mips_elf_acom_symbol_ptr;
 
-/* The Irix 5 support uses two virtual sections, which represent
-   text/data symbols defined in dynamic objects.  */
-static asection mips_elf_text_section;
-static asection *mips_elf_text_section_ptr;
-static asymbol mips_elf_text_symbol;
-static asymbol *mips_elf_text_symbol_ptr;
-
-static asection mips_elf_data_section;
-static asection *mips_elf_data_section_ptr;
-static asymbol mips_elf_data_symbol;
-static asymbol *mips_elf_data_symbol_ptr;
-
 /* Handle the special MIPS section numbers that a symbol may use.
    This is used for both the 32-bit and the 64-bit ABI.  */
 
@@ -3786,6 +3874,27 @@ mips_elf_link_hash_newfunc (entry, table, string)
   return (struct bfd_hash_entry *) ret;
 }
 
+void
+_bfd_mips_elf_hide_symbol(info, h)
+     struct bfd_link_info *info;
+     struct mips_elf_link_hash_entry *h;
+{
+  bfd *dynobj;
+  asection *got;
+  struct mips_got_info *g;
+  dynobj = elf_hash_table (info)->dynobj;
+  got = bfd_get_section_by_name (dynobj, ".got");
+  g = (struct mips_got_info *) elf_section_data (got)->tdata;
+
+  h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+  h->root.plt.offset = (bfd_vma) -1;
+  h->root.dynindx = -1;
+
+  /* FIXME: Do we allocate too much GOT space here?  */
+  g->local_gotno++;
+  got->_raw_size += MIPS_ELF_GOT_SIZE (dynobj);
+}
+
 /* Create a MIPS ELF linker hash table.  */
 
 struct bfd_link_hash_table *
@@ -3860,48 +3969,78 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 
     case SHN_MIPS_TEXT:
       /* This section is used in a shared object.  */
-      if (mips_elf_text_section_ptr == NULL)
+      if (elf_tdata (abfd)->elf_text_section == NULL)
        {
+         asymbol *elf_text_symbol;
+         asection *elf_text_section;
+
+         elf_text_section = bfd_zalloc (abfd, sizeof (asection));
+         if (elf_text_section == NULL)
+           return false;
+
+         elf_text_symbol = bfd_zalloc (abfd, sizeof (asymbol));
+         if (elf_text_symbol == NULL)
+           return false;
+
          /* Initialize the section.  */
-         mips_elf_text_section.name = ".text";
-         mips_elf_text_section.flags = SEC_NO_FLAGS;
-         mips_elf_text_section.output_section = NULL;
-         mips_elf_text_section.symbol = &mips_elf_text_symbol;
-         mips_elf_text_section.symbol_ptr_ptr = &mips_elf_text_symbol_ptr;
-         mips_elf_text_symbol.name = ".text";
-         mips_elf_text_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
-         mips_elf_text_symbol.section = &mips_elf_text_section;
-         mips_elf_text_symbol_ptr = &mips_elf_text_symbol;
-         mips_elf_text_section_ptr = &mips_elf_text_section;
+
+         elf_tdata (abfd)->elf_text_section = elf_text_section;
+         elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
+
+         elf_text_section->symbol = elf_text_symbol;
+         elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol;
+
+         elf_text_section->name = ".text";
+         elf_text_section->flags = SEC_NO_FLAGS;
+         elf_text_section->output_section = NULL;
+         elf_text_section->owner = abfd;
+         elf_text_symbol->name = ".text";
+         elf_text_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC;
+         elf_text_symbol->section = elf_text_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
          info->shared.  I don't know why, and that doesn't make sense,
          so I took it out.  */
-      *secp = mips_elf_text_section_ptr;
+      *secp = elf_tdata (abfd)->elf_text_section;
       break;
 
     case SHN_MIPS_ACOMMON:
       /* Fall through. XXX Can we treat this as allocated data?  */
     case SHN_MIPS_DATA:
       /* This section is used in a shared object.  */
-      if (mips_elf_data_section_ptr == NULL)
+      if (elf_tdata (abfd)->elf_data_section == NULL)
        {
+         asymbol *elf_data_symbol;
+         asection *elf_data_section;
+
+         elf_data_section = bfd_zalloc (abfd, sizeof (asection));
+         if (elf_data_section == NULL)
+           return false;
+
+         elf_data_symbol = bfd_zalloc (abfd, sizeof (asymbol));
+         if (elf_data_symbol == NULL)
+           return false;
+
          /* Initialize the section.  */
-         mips_elf_data_section.name = ".data";
-         mips_elf_data_section.flags = SEC_NO_FLAGS;
-         mips_elf_data_section.output_section = NULL;
-         mips_elf_data_section.symbol = &mips_elf_data_symbol;
-         mips_elf_data_section.symbol_ptr_ptr = &mips_elf_data_symbol_ptr;
-         mips_elf_data_symbol.name = ".data";
-         mips_elf_data_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
-         mips_elf_data_symbol.section = &mips_elf_data_section;
-         mips_elf_data_symbol_ptr = &mips_elf_data_symbol;
-         mips_elf_data_section_ptr = &mips_elf_data_section;
+
+         elf_tdata (abfd)->elf_data_section = elf_data_section;
+         elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
+
+         elf_data_section->symbol = elf_data_symbol;
+         elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol;
+
+         elf_data_section->name = ".data";
+         elf_data_section->flags = SEC_NO_FLAGS;
+         elf_data_section->output_section = NULL;
+         elf_data_section->owner = abfd;
+         elf_data_symbol->name = ".data";
+         elf_data_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC;
+         elf_data_symbol->section = elf_data_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
          info->shared.  I don't know why, and that doesn't make sense,
          so I took it out.  */
-      *secp = mips_elf_data_section_ptr;
+      *secp = elf_tdata (abfd)->elf_data_section;
       break;
 
     case SHN_MIPS_SUNDEFINED:
@@ -5007,6 +5146,26 @@ _bfd_mips_elf_final_link (abfd, info)
   return true;
 }
 
+/* This function is called via qsort() to sort the dynamic relocation
+   entries by increasing r_symndx value.  */
+
+static int
+sort_dynamic_relocs (arg1,arg2)
+        const PTR arg1;
+        const PTR arg2;
+{
+  const Elf32_External_Rel *ext_reloc1 = (const Elf32_External_Rel *) arg1;
+  const Elf32_External_Rel *ext_reloc2 = (const Elf32_External_Rel *) arg2;
+
+  Elf_Internal_Rel int_reloc1;
+  Elf_Internal_Rel int_reloc2;
+
+  bfd_elf32_swap_reloc_in(reldyn_sorting_bfd, ext_reloc1, &int_reloc1);
+  bfd_elf32_swap_reloc_in(reldyn_sorting_bfd, ext_reloc2, &int_reloc2);
+
+  return (ELF32_R_SYM(int_reloc1.r_info) - ELF32_R_SYM(int_reloc2.r_info));
+}
+
 /* Returns the GOT section for ABFD.  */
 
 static asection *
@@ -5042,24 +5201,42 @@ mips_elf_got_info (abfd, sgotp)
 /* Return whether a relocation is against a local symbol.  */
 
 static boolean
-mips_elf_local_relocation_p (input_bfd, relocation, local_sections)
+mips_elf_local_relocation_p (input_bfd, relocation, local_sections,
+                            check_forced)
      bfd *input_bfd;
      const Elf_Internal_Rela *relocation;
      asection **local_sections;
+     boolean check_forced;
 {
   unsigned long r_symndx;
   Elf_Internal_Shdr *symtab_hdr;
+  struct mips_elf_link_hash_entry* h;
+  size_t extsymoff;
 
   r_symndx = ELF32_R_SYM (relocation->r_info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-  if (! elf_bad_symtab (input_bfd))
-    return r_symndx < symtab_hdr->sh_info;
-  else
+  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
+
+  if (r_symndx < extsymoff)
+    return true;
+  if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
+    return true;
+
+  if (check_forced)
     {
-      /* The symbol table does not follow the rule that local symbols
-        must come before globals.  */
-      return local_sections[r_symndx] != NULL;
+       /* Look up the hash table to check whether the symbol
+        was forced local.  */
+       h = (struct mips_elf_link_hash_entry *)
+         elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
+       /* Find the real hash-table entry for this symbol.  */
+       while (h->root.root.type == bfd_link_hash_indirect
+            || h->root.root.type == bfd_link_hash_warning)
+         h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+       if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+         return true;
     }
+
+  return false;
 }
 
 /* Sign-extend VALUE, which has the indicated number of BITS.  */
@@ -5278,7 +5455,7 @@ mips_elf_sort_hash_table (info, max_local)
 
   /* There shoud have been enough room in the symbol table to
      accomodate both the GOT and non-GOT symbols.  */
-  BFD_ASSERT (hsd.min_got_dynindx == hsd.max_non_got_dynindx);
+  BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
 
   /* Now we know which dynamic symbol has the lowest dynamic symbol
      table index in the GOT.  */
@@ -5360,7 +5537,7 @@ mips_elf_got_page (abfd, info, value, offsetp)
   struct mips_got_info *g;
   bfd_byte *entry;
   bfd_byte *last_entry;
-  bfd_vma index;
+  bfd_vma index = 0;
   bfd_vma address;
 
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
@@ -5400,23 +5577,28 @@ mips_elf_got_page (abfd, info, value, offsetp)
    for value.  Return the index into the GOT for this entry.  */
 
 static bfd_vma
-mips_elf_got16_entry (abfd, info, value)
+mips_elf_got16_entry (abfd, info, value, external)
      bfd *abfd;
      struct bfd_link_info *info;
      bfd_vma value;
+     boolean external;
 {
   asection *sgot;
   struct mips_got_info *g;
   bfd_byte *entry;
   bfd_byte *last_entry;
-  bfd_vma index;
+  bfd_vma index = 0;
   bfd_vma address;
 
-  /* Although the ABI says that it is "the high-order 16 bits" that we
-     want, it is really the %high value.  The complete value is
-     calculated with a `addiu' of a LO16 relocation, just as with a
-     HI16/LO16 pair.  */
-  value = mips_elf_high (value) << 16;
+  if (! external)
+    {
+      /* Although the ABI says that it is "the high-order 16 bits" that we
+        want, it is really the %high value.  The complete value is
+        calculated with a `addiu' of a LO16 relocation, just as with a
+        HI16/LO16 pair.  */
+      value = mips_elf_high (value) << 16;
+    }
+
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
   /* Look to see if we already have an appropriate entry.  */
@@ -5427,9 +5609,10 @@ mips_elf_got16_entry (abfd, info, value)
        entry += MIPS_ELF_GOT_SIZE (abfd))
     {
       address = MIPS_ELF_GET_WORD (abfd, entry);
-      if ((address & 0xffff0000) == value)
+      if (address == value)
        {
-         /* This entry has the right high-order 16 bits.  */
+         /* This entry has the right high-order 16 bits, and the low-order
+            16 bits are set to zero.  */
          index = entry - sgot->contents;
          break;
        }
@@ -5442,11 +5625,12 @@ mips_elf_got16_entry (abfd, info, value)
   return index;
 }
 
-/* Returns the first R_MIPS_LO16 relocation found, beginning with
+/* Returns the first relocation of type r_type found, beginning with
    RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
 
 static const Elf_Internal_Rela *
-mips_elf_next_lo16_relocation (relocation, relend)
+mips_elf_next_relocation (r_type, relocation, relend)
+     unsigned int r_type;
      const Elf_Internal_Rela *relocation;
      const Elf_Internal_Rela *relend;
 {
@@ -5458,7 +5642,7 @@ mips_elf_next_lo16_relocation (relocation, relend)
      extension in general, as that is useful for GCC.  */
   while (relocation < relend)
     {
-      if (ELF32_R_TYPE (relocation->r_info) == R_MIPS_LO16)
+      if (ELF32_R_TYPE (relocation->r_info) == r_type)
        return relocation;
 
       ++relocation;
@@ -5471,7 +5655,7 @@ mips_elf_next_lo16_relocation (relocation, relend)
 
 /* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
    is the original relocation, which is now being transformed into a
-   dyanmic relocation.  The ADDENDP is adjusted if necessary; the
+   dynamic relocation.  The ADDENDP is adjusted if necessary; the
    caller should store the result in place of the original addend.  */
 
 static boolean
@@ -5498,6 +5682,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
     = bfd_get_section_by_name (dynobj,
                               MIPS_ELF_REL_DYN_SECTION_NAME (output_bfd));
   BFD_ASSERT (sreloc != NULL);
+  BFD_ASSERT (sreloc->contents != NULL);
 
   skip = false;
 
@@ -5524,7 +5709,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
        skip = true;
     }
 
-  /* If we've decided to skip this relocation, just output an emtpy
+  /* If we've decided to skip this relocation, just output an empty
      record.  Note that R_MIPS_NONE == 0, so that this call to memset
      is a way of setting R_TYPE to R_MIPS_NONE.  */
   if (skip)
@@ -5541,7 +5726,10 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
                                   & ELF_LINK_HASH_DEF_REGULAR) == 0))
        {
          indx = h->root.dynindx;
-         BFD_ASSERT (indx != -1);
+         /* h->root.dynindx may be -1 if this symbol was marked to
+            become local.  */
+         if (indx == -1)
+               indx = 0;
        }
       else
        {
@@ -5739,7 +5927,7 @@ mips_elf_calculate_relocation (abfd,
      used in the array of hash table entries.  */
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   local_p = mips_elf_local_relocation_p (input_bfd, relocation,
-                                        local_sections);
+                                        local_sections, false);
   if (! elf_bad_symtab (input_bfd))
     extsymoff = symtab_hdr->sh_info;
   else
@@ -5780,8 +5968,8 @@ mips_elf_calculate_relocation (abfd,
       h = ((struct mips_elf_link_hash_entry *) 
           elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
       /* Find the real hash-table entry for this symbol.  */
-      while (h->root.type == bfd_link_hash_indirect
-            || h->root.type == bfd_link_hash_warning)
+      while (h->root.root.type == bfd_link_hash_indirect
+            || h->root.root.type == bfd_link_hash_warning)
        h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
       
       /* Record the name of this symbol, for our caller.  */
@@ -5820,7 +6008,8 @@ mips_elf_calculate_relocation (abfd,
           and check to see if they exist by looking at their
           addresses.  */
        symbol = 0;
-      else if (info->shared && !info->symbolic && !info->no_undefined)
+      else if (info->shared && !info->symbolic && !info->no_undefined
+              && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
        symbol = 0;
       else if (strcmp (h->root.root.root.string, "_DYNAMIC_LINK") == 0)
        {
@@ -5838,7 +6027,8 @@ mips_elf_calculate_relocation (abfd,
          if (! ((*info->callbacks->undefined_symbol)
                 (info, h->root.root.root.string, input_bfd,
                  input_section, relocation->r_offset,
-                 (!info->shared || info->no_undefined))))
+                 (!info->shared || info->no_undefined
+                  || ELF_ST_VISIBILITY (h->root.other)))))
            return bfd_reloc_undefined;
          symbol = 0;
        }
@@ -5909,6 +6099,9 @@ mips_elf_calculate_relocation (abfd,
   *require_jalxp = (!info->relocateable
                    && ((r_type == R_MIPS16_26) != target_is_16_bit_code_p));
 
+  local_p = mips_elf_local_relocation_p (input_bfd, relocation,
+                                        local_sections, true);
+
   /* If we haven't already determined the GOT offset, or the GP value,
      and we're going to need it, get it now.  */
   switch (r_type)
@@ -5927,6 +6120,19 @@ mips_elf_calculate_relocation (abfd,
          g = mips_elf_global_got_index 
            (elf_hash_table (info)->dynobj,
             (struct elf_link_hash_entry*) h);
+         if (! elf_hash_table(info)->dynamic_sections_created
+             || (info->shared
+                 && (info->symbolic || h->root.dynindx == -1)
+                 && (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+           {
+             /* This is a static link or a -Bsymbolic link.  The
+                symbol is defined locally, or was forced to be local.
+                We must initialize this entry in the GOT.  */
+             asection *sgot = mips_elf_got_section(elf_hash_table
+                                                   (info)->dynobj);
+             MIPS_ELF_PUT_WORD (elf_hash_table (info)->dynobj,
+                                symbol + addend, sgot->contents + g);
+           }
        }
       else if (r_type == R_MIPS_GOT16)
        /* There's no need to create a local GOT entry here; the
@@ -5974,8 +6180,8 @@ mips_elf_calculate_relocation (abfd,
       if ((info->shared
           || (elf_hash_table (info)->dynamic_sections_created
               && h != NULL
-              && ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
-                  == 0)))
+              && ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+                  != 0)))
          && (input_section->flags & SEC_ALLOC) != 0)
        {
          /* If we're creating a shared library, or this relocation is
@@ -6004,6 +6210,24 @@ mips_elf_calculate_relocation (abfd,
       value &= howto->dst_mask;
       break;
 
+    case R_MIPS_PC32:
+    case R_MIPS_PC64:
+    case R_MIPS_GNU_REL_LO16:
+      value = symbol + addend - p;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_GNU_REL16_S2:
+      value = symbol + mips_elf_sign_extend (addend << 2, 18) - p;
+      overflowed_p = mips_elf_overflow_p (value, 18);
+      value = (value >> 2) & howto->dst_mask;
+      break;
+
+    case R_MIPS_GNU_REL_HI16:
+      value = mips_elf_high (addend + symbol - p);
+      value &= howto->dst_mask;
+      break;
+
     case R_MIPS16_26:
       /* The calculation for R_MIPS_26 is just the same as for an
         R_MIPS_26.  It's only the storage of the relocated field into
@@ -6080,7 +6304,14 @@ mips_elf_calculate_relocation (abfd,
     case R_MIPS_GOT16:
       if (local_p)
        {
-         value = mips_elf_got16_entry (abfd, info, symbol + addend);
+         boolean forced;
+         
+         /* The special case is when the symbol is forced to be local.  We
+            need the full address in the GOT since no R_MIPS_LO16 relocation
+            follows.  */
+         forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
+                                                 local_sections, false);
+         value = mips_elf_got16_entry (abfd, info, symbol + addend, forced);
          if (value == (bfd_vma) -1)
            return false;
          value 
@@ -6415,7 +6646,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 {
   Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *relend;
-  bfd_vma addend;
+  bfd_vma addend = 0;
   boolean use_saved_addend_p = false;
   struct elf_backend_data *bed;
 
@@ -6482,13 +6713,15 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 combination of the addend stored in two different
                 relocations.   */
              if (r_type == R_MIPS_HI16
+                 || r_type == R_MIPS_GNU_REL_HI16
                  || (r_type == R_MIPS_GOT16
                      && mips_elf_local_relocation_p (input_bfd, rel,
-                                                     local_sections)))
+                                                     local_sections, false)))
                {
                  bfd_vma l;
                  const Elf_Internal_Rela *lo16_relocation;
                  reloc_howto_type *lo16_howto;
+                 int lo;
 
                  /* The combined value is the sum of the HI16 addend,
                     left-shifted by sixteen bits, and the LO16
@@ -6496,15 +6729,18 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                     a `lui' of the HI16 value, and then an `addiu' of
                     the LO16 value.)  
 
-                    Scan ahead to find a matching R_MIPS_LO16
-                    relocation.  */
+                    Scan ahead to find a matching LO16 relocation.  */
+                 if (r_type == R_MIPS_GNU_REL_HI16)
+                   lo = R_MIPS_GNU_REL_LO16;
+                 else
+                   lo = R_MIPS_LO16;
                  lo16_relocation 
-                   = mips_elf_next_lo16_relocation (rel, relend); 
+                   = mips_elf_next_relocation (lo, rel, relend); 
                  if (lo16_relocation == NULL)
                    return false;
 
                  /* Obtain the addend kept there.  */
-                 lo16_howto = mips_rtype_to_howto (R_MIPS_LO16);
+                 lo16_howto = mips_rtype_to_howto (lo);
                  l = mips_elf_obtain_contents (lo16_howto,
                                                lo16_relocation,
                                                input_bfd, contents);
@@ -6535,6 +6771,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          Elf_Internal_Sym *sym;
          unsigned long r_symndx;
 
+         if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd)
+             && bfd_big_endian (input_bfd))
+           rel->r_offset -= 4;
+
          /* Since we're just relocating, all we need to do is copy
             the relocations back out to the object file, unless
             they're against a section symbol, in which case we need
@@ -6542,7 +6782,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             relative in which case we need to adjust by the amount
             that we're adjusting GP in this relocateable object.  */
 
-         if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+         if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections,
+                                           false))
            /* There's nothing to do for non-local relocations.  */
            continue;
 
@@ -6552,7 +6793,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              || r_type == R_MIPS_LITERAL)
            addend -= (_bfd_get_gp_value (output_bfd)
                       - _bfd_get_gp_value (input_bfd));
-         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26)
+         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26
+                  || r_type == R_MIPS_GNU_REL16_S2)
            /* The addend is stored without its two least
               significant bits (which are always zero.)  In a
               non-relocateable link, calculate_relocation will do
@@ -6568,17 +6810,19 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
             then we only want to write out the high-order 16 bits.
             The subsequent R_MIPS_LO16 will handle the low-order bits.  */
-         if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
+         if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16
+             || r_type == R_MIPS_GNU_REL_HI16)
            addend = mips_elf_high (addend);
          /* If the relocation is for an R_MIPS_26 relocation, then
             the two low-order bits are not stored in the object file;
             they are implicitly zero.  */
-         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26)
+         else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26
+                  || r_type == R_MIPS_GNU_REL16_S2)
            addend >>= 2;
 
          if (rela_relocation_p)
            /* If this is a RELA relocation, just update the addend.
-               We have to cast away constness for REL.  */
+              We have to cast away constness for REL.  */
            rel->r_addend = addend;
          else
            {
@@ -6588,6 +6832,43 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 writing will be source of the addend in the final
                 link.  */
              addend &= howto->src_mask;
+
+             if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
+               /* See the comment above about using R_MIPS_64 in the 32-bit
+                  ABI.  Here, we need to update the addend.  It would be
+                  possible to get away with just using the R_MIPS_32 reloc
+                  but for endianness.  */
+               {
+                 bfd_vma sign_bits;
+                 bfd_vma low_bits;
+                 bfd_vma high_bits;
+                 
+                 if (addend & ((bfd_vma) 1 << 31))
+                   sign_bits = ((bfd_vma) 1 << 32) - 1;
+                 else
+                   sign_bits = 0;
+                 
+                 /* If we don't know that we have a 64-bit type,
+                    do two separate stores.  */
+                 if (bfd_big_endian (input_bfd))
+                   {
+                     /* Store the sign-bits (which are most significant)
+                        first.  */
+                     low_bits = sign_bits;
+                     high_bits = addend;
+                   }
+                 else
+                   {
+                     low_bits = addend;
+                     high_bits = sign_bits;
+                   }
+                 bfd_put_32 (input_bfd, low_bits, 
+                             contents + rel->r_offset);
+                 bfd_put_32 (input_bfd, high_bits, 
+                             contents + rel->r_offset + 4);
+                 continue;
+               }
+
              if (!mips_elf_perform_relocation (info, howto, rel, addend,
                                                input_bfd,  input_section, 
                                                contents, false))
@@ -6629,7 +6910,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
        case bfd_reloc_undefined:
          /* mips_elf_calculate_relocation already called the
-             undefined_symbol callback.  There's no real point in
+            undefined_symbol callback.  There's no real point in
             trying to perform the relocation at this point, so we
             just skip ahead to the next relocation.  */
          continue;
@@ -6682,13 +6963,13 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          bfd_vma low_bits;
          bfd_vma high_bits;
 
-         if (value & 0x80000000)
-           sign_bits = 0xffffffff;
+         if (value & ((bfd_vma) 1 << 31))
+           sign_bits = ((bfd_vma) 1 << 32) - 1;
          else
            sign_bits = 0;
 
-         /* If only a 32-bit VMA is available do two separate
-            stores.  */
+         /* If we don't know that we have a 64-bit type,
+            do two separate stores.  */
          if (bfd_big_endian (input_bfd))
            {
              /* Undo what we did above.  */
@@ -7573,6 +7854,26 @@ _bfd_mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
   return true;
 }
 
+/* Copy data from a MIPS ELF indirect symbol to its direct symbol,
+   hiding the old indirect symbol.  Process additional relocation
+   information.  */
+
+void
+_bfd_mips_elf_copy_indirect_symbol (dir, ind)
+     struct elf_link_hash_entry *dir, *ind;
+{
+  struct mips_elf_link_hash_entry *dirmips, *indmips;
+
+  _bfd_elf_link_hash_copy_indirect (dir, ind);
+
+  dirmips = (struct mips_elf_link_hash_entry *) dir;
+  indmips = (struct mips_elf_link_hash_entry *) ind;
+  dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
+  if (dirmips->min_dyn_reloc_index == 0
+      || (indmips->min_dyn_reloc_index != 0
+          && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
+    dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+}
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
@@ -8168,7 +8469,8 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       sym->st_value = gval;
     }
 
-  BFD_ASSERT (h->dynindx != -1);
+  BFD_ASSERT (h->dynindx != -1
+             || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0);
 
   sgot = mips_elf_got_section (dynobj);
   BFD_ASSERT (sgot != NULL);
@@ -8560,6 +8862,23 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
          }
       }
 
+    /* We need to sort the entries of the dynamic relocation section.  */
+
+    if (!ABI_64_P (output_bfd))
+      {
+            asection *reldyn;
+
+            reldyn = bfd_get_section_by_name (dynobj,
+                                     MIPS_ELF_REL_DYN_SECTION_NAME (dynobj));
+            if (reldyn != NULL && reldyn->reloc_count > 2)
+              {
+                reldyn_sorting_bfd = output_bfd;
+                qsort ((Elf32_External_Rel *) reldyn->contents + 1,
+                       (size_t) reldyn->reloc_count - 1,
+                       sizeof (Elf32_External_Rel), sort_dynamic_relocs);
+              }
+      }
+
     /* Clean up a first relocation in .rel.dyn.  */
     s = bfd_get_section_by_name (dynobj, 
                                 MIPS_ELF_REL_DYN_SECTION_NAME (dynobj));
@@ -8853,6 +9172,11 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 #define elf_backend_got_header_size    (4*MIPS_RESERVED_GOTNO)
 #define elf_backend_plt_header_size    0
 
+#define elf_backend_copy_indirect_symbol \
+                                       _bfd_mips_elf_copy_indirect_symbol
+
+#define elf_backend_hide_symbol                _bfd_mips_elf_hide_symbol
+
 #define bfd_elf32_bfd_is_local_label_name \
                                        mips_elf_is_local_label_name
 #define bfd_elf32_find_nearest_line    _bfd_mips_elf_find_nearest_line
@@ -8868,3 +9192,20 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 #define bfd_elf32_bfd_print_private_bfd_data \
                                        _bfd_mips_elf_print_private_bfd_data
 #include "elf32-target.h"
+
+/* Support for traditional mips targets */
+
+#define INCLUDED_TARGET_FILE            /* More a type of flag */
+
+#undef TARGET_LITTLE_SYM
+#undef TARGET_LITTLE_NAME
+#undef TARGET_BIG_SYM
+#undef TARGET_BIG_NAME
+
+#define TARGET_LITTLE_SYM               bfd_elf32_tradlittlemips_vec
+#define TARGET_LITTLE_NAME              "elf32-tradlittlemips"
+#define TARGET_BIG_SYM                  bfd_elf32_tradbigmips_vec
+#define TARGET_BIG_NAME                 "elf32-tradbigmips"
+
+/* Include the target file again for this target */
+#include "elf32-target.h"
This page took 0.034376 seconds and 4 git commands to generate.