Revise way in which mappings are allocated/searched.
[deliverable/binutils-gdb.git] / bfd / elf32-mips.c
index b58eddf5c9c86260024ab6bc93fe46ebbf93bc6f..b90178e519b0620040f7ce35be14be0b5a850bf3 100644 (file)
@@ -1,5 +1,5 @@
 /* MIPS-specific support for 32-bit ELF
-   Copyright 1993, 94, 95, 96, 97, 98, 99, 2000
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
@@ -49,7 +49,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 /* This structure is used to hold .got information when linking.  It
    is stored in the tdata field of the bfd_elf_section_data structure.  */
 
-struct mips_got_info {
+struct mips_got_info
+{
   /* The global symbol in the GOT with the lowest index in the dynamic
      symbol table.  */
   struct elf_link_hash_entry *global_gotsym;
@@ -64,7 +65,8 @@ struct mips_got_info {
 /* The MIPS ELF linker needs additional information for each symbol in
    the global hash table.  */
 
-struct mips_elf_link_hash_entry {
+struct mips_elf_link_hash_entry
+{
   struct elf_link_hash_entry root;
 
   /* External symbol information.  */
@@ -78,6 +80,12 @@ struct mips_elf_link_hash_entry {
      section) against this symbol.  */
   unsigned int min_dyn_reloc_index;
 
+  /* We must not create a stub for a symbol that has relocations
+     related to taking the function's address, i.e. any but
+     R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+     p. 4-20.  */
+  boolean no_fn_stub;
+
   /* If there is a stub that 32 bit functions should use to call this
      16 bit function, this points to the section containing the stub.  */
   asection *fn_stub;
@@ -191,7 +199,7 @@ static bfd_vma mips_elf_got16_entry
 static boolean mips_elf_create_dynamic_relocation
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
           struct mips_elf_link_hash_entry *, asection *,
-          bfd_vma, bfd_vma *, asection *, boolean local_p));
+          bfd_vma, bfd_vma *, asection *));
 static void mips_elf_allocate_dynamic_relocations
   PARAMS ((bfd *, unsigned int));
 static boolean mips_elf_stub_section_p
@@ -200,6 +208,9 @@ static int sort_dynamic_relocs
   PARAMS ((const void *, const void *));
 
 extern const bfd_target bfd_elf32_tradbigmips_vec;
+extern const bfd_target bfd_elf32_tradlittlemips_vec;
+extern const bfd_target bfd_elf64_tradbigmips_vec;
+extern const bfd_target bfd_elf64_tradlittlemips_vec;
 
 /* The level of IRIX compatibility we're striving for.  */
 
@@ -217,8 +228,7 @@ static bfd *reldyn_sorting_bfd;
 #define ABI_N32_P(abfd) \
   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
 
-/* Nonzero if ABFD is using the 64-bit ABI.  FIXME: This is never
-   true, yet.  */
+/* Nonzero if ABFD is using the 64-bit ABI. */
 #define ABI_64_P(abfd) \
   ((elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) != 0)
 
@@ -226,7 +236,10 @@ static bfd *reldyn_sorting_bfd;
    executables or "normal" MIPS ELF ABI executables.  */
 
 #define IRIX_COMPAT(abfd) \
-  (abfd->xvec == &bfd_elf32_tradbigmips_vec ? ict_none : \
+  (((abfd->xvec == &bfd_elf64_tradbigmips_vec) || \
+    (abfd->xvec == &bfd_elf64_tradlittlemips_vec) || \
+    (abfd->xvec == &bfd_elf32_tradbigmips_vec) || \
+    (abfd->xvec == &bfd_elf32_tradlittlemips_vec)) ? ict_none : \
   ((ABI_N32_P (abfd) || ABI_64_P (abfd)) ? ict_irix6 : ict_irix5))
 
 /* Whether we are trying to be compatible with IRIX at all.  */
@@ -321,7 +334,8 @@ static bfd *reldyn_sorting_bfd;
 /* Names of sections which appear in the .dynsym section in an Irix 5
    executable.  */
 
-static const char * const mips_elf_dynsym_sec_names[] = {
+static const char * const mips_elf_dynsym_sec_names[] =
+{
   ".text",
   ".init",
   ".fini",
@@ -345,7 +359,8 @@ static const char * const mips_elf_dynsym_sec_names[] = {
 
 /* The names of the runtime procedure table symbols used on Irix 5.  */
 
-static const char * const mips_elf_dynsym_rtproc_names[] = {
+static const char * const mips_elf_dynsym_rtproc_names[] =
+{
   "_procedure_table",
   "_procedure_string_table",
   "_procedure_table_size",
@@ -355,7 +370,8 @@ static const char * const mips_elf_dynsym_rtproc_names[] = {
 /* These structures are used to generate the .compact_rel section on
    Irix 5.  */
 
-typedef struct {
+typedef struct
+{
   unsigned long id1;           /* Always one?  */
   unsigned long num;           /* Number of compact relocation entries.  */
   unsigned long id2;           /* Always two?  */
@@ -364,7 +380,8 @@ typedef struct {
   unsigned long reserved1;     /* Zero?  */
 } Elf32_compact_rel;
 
-typedef struct {
+typedef struct
+{
   bfd_byte id1[4];
   bfd_byte num[4];
   bfd_byte id2[4];
@@ -373,7 +390,8 @@ typedef struct {
   bfd_byte reserved1[4];
 } Elf32_External_compact_rel;
 
-typedef struct {
+typedef struct
+{
   unsigned int ctype : 1;      /* 1: long 0: short format. See below.  */
   unsigned int rtype : 4;      /* Relocation types. See below.  */
   unsigned int dist2to : 8;
@@ -382,7 +400,8 @@ typedef struct {
   unsigned long vaddr;         /* VADDR to be relocated.  */
 } Elf32_crinfo;
 
-typedef struct {
+typedef struct
+{
   unsigned int ctype : 1;      /* 1: long 0: short format. See below.  */
   unsigned int rtype : 4;      /* Relocation types. See below.  */
   unsigned int dist2to : 8;
@@ -390,13 +409,15 @@ typedef struct {
   unsigned long konst;         /* KONST field. See below.  */
 } Elf32_crinfo2;
 
-typedef struct {
+typedef struct
+{
   bfd_byte info[4];
   bfd_byte konst[4];
   bfd_byte vaddr[4];
 } Elf32_External_crinfo;
 
-typedef struct {
+typedef struct
+{
   bfd_byte info[4];
   bfd_byte konst[4];
 } Elf32_External_crinfo2;
@@ -449,7 +470,8 @@ static void bfd_elf32_swap_crinfo_out
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 
-static reloc_howto_type elf_mips_howto_table[] = {
+static reloc_howto_type elf_mips_howto_table[] =
+{
   /* No relocation.  */
   HOWTO (R_MIPS_NONE,          /* type */
         0,                     /* rightshift */
@@ -520,7 +542,7 @@ static reloc_howto_type elf_mips_howto_table[] = {
         complain_overflow_dont, /* complain_on_overflow */
                                /* This needs complex overflow
                                   detection, because the upper four
-                                  bits must match the PC.  */
+                                  bits must match the PC + 4.  */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIPS_26",           /* name */
         true,                  /* partial_inplace */
@@ -1067,7 +1089,8 @@ static reloc_howto_type elf_mips_gnu_vtentry_howto =
    reloc.  This extension permits gcc to output the HI and LO relocs
    itself.  */
 
-struct mips_hi16 {
+struct mips_hi16
+{
   struct mips_hi16 *next;
   bfd_byte *addr;
   bfd_vma addend;
@@ -1810,8 +1833,12 @@ elf_mips_isa (flags)
       return 3;
     case E_MIPS_ARCH_4:
       return 4;
+    case E_MIPS_ARCH_5:
+      return 5;
     case E_MIPS_ARCH_32:
       return 32;
+    case E_MIPS_ARCH_64:
+      return 64;
     }
   return 4;
 }
@@ -1842,6 +1869,9 @@ elf_mips_mach (flags)
     case E_MIPS_MACH_MIPS32_4K:
       return bfd_mach_mips32_4k;
 
+    case E_MIPS_MACH_SB1:
+      return bfd_mach_mips_sb1;
+
     default:
       switch (flags & EF_MIPS_ARCH)
        {
@@ -1862,9 +1892,17 @@ elf_mips_mach (flags)
          return bfd_mach_mips8000;
          break;
 
+       case E_MIPS_ARCH_5:
+         return bfd_mach_mips5;
+         break;
+
        case E_MIPS_ARCH_32:
          return bfd_mach_mips32;
          break;
+
+       case E_MIPS_ARCH_64:
+         return bfd_mach_mips64;
+         break;
        }
     }
 
@@ -1909,7 +1947,8 @@ struct elf_reloc_map {
   enum elf_mips_reloc_type elf_reloc_val;
 };
 
-static CONST struct elf_reloc_map mips_reloc_map[] = {
+static CONST struct elf_reloc_map mips_reloc_map[] =
+{
   { BFD_RELOC_NONE, R_MIPS_NONE, },
   { BFD_RELOC_16, R_MIPS_16 },
   { BFD_RELOC_32, R_MIPS_32 },
@@ -2267,7 +2306,12 @@ mips_elf_sym_is_global (abfd, sym)
      bfd *abfd ATTRIBUTE_UNUSED;
      asymbol *sym;
 {
-  return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
+  if (SGI_COMPAT(abfd))
+    return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
+  else
+    return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+            || bfd_is_und_section (bfd_get_section (sym))
+            || bfd_is_com_section (bfd_get_section (sym)));
 }
 \f
 /* Set the right machine number for a MIPS ELF file.  This is used for
@@ -2349,6 +2393,18 @@ _bfd_mips_elf_final_write_processing (abfd, linker)
     case bfd_mach_mips32_4k:
       val = E_MIPS_ARCH_32 | E_MIPS_MACH_MIPS32_4K;
       break;
+
+    case bfd_mach_mips5:
+      val = E_MIPS_ARCH_5;
+      break;
+
+    case bfd_mach_mips64:
+      val = E_MIPS_ARCH_64;
+      break;
+
+    case bfd_mach_mips_sb1:
+      val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
+      break;
     }
 
   elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
@@ -2470,6 +2526,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
   flagword old_flags;
   flagword new_flags;
   boolean ok;
+  boolean null_input_bfd = true;
+  asection *sec;
 
   /* Check if we have the same endianess */
   if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
@@ -2509,6 +2567,27 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
   if (new_flags == old_flags)
     return true;
 
+  /* Check to see if the input BFD actually contains any sections.
+     If not, its flags may not have been initialised either, but it cannot
+     actually cause any incompatibility.  */
+  for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+    {
+      /* Ignore synthetic sections and empty .text, .data and .bss sections
+         which are automatically generated by gas.  */
+      if (strcmp (sec->name, ".reginfo")
+         && strcmp (sec->name, ".mdebug")
+         && ((!strcmp (sec->name, ".text")
+              || !strcmp (sec->name, ".data")
+              || !strcmp (sec->name, ".bss"))
+             && sec->_raw_size != 0))
+       {
+         null_input_bfd = false;
+         break;
+       }
+    }
+  if (null_input_bfd)
+    return true;
+
   ok = true;
 
   if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC))
@@ -2656,8 +2735,12 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr)
     fprintf (file, _(" [mips3]"));
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4)
     fprintf (file, _(" [mips4]"));
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_5)
+    fprintf (file, _ (" [mips5]"));
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32)
     fprintf (file, _ (" [mips32]"));
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64)
+    fprintf (file, _ (" [mips64]"));
   else
     fprintf (file, _(" [unknown ISA]"));
 
@@ -3437,7 +3520,8 @@ _bfd_mips_elf_modify_segment_map (abfd)
       if (m != NULL
          && m->count == 1 && strcmp (m->sections[0]->name, ".dynamic") == 0)
        {
-         static const char *sec_names[] = {
+         static const char *sec_names[] =
+         {
            ".dynamic", ".dynstr", ".dynsym", ".hash"
          };
          bfd_vma low, high;
@@ -3656,7 +3740,8 @@ mips_elf_is_local_label_name (abfd, name)
 /* MIPS ELF uses a special find_nearest_line routine in order the
    handle the ECOFF debugging information.  */
 
-struct mips_elf_find_line {
+struct mips_elf_find_line
+{
   struct ecoff_debug_info d;
   struct ecoff_find_line i;
 };
@@ -3682,7 +3767,8 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
   if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
                                     filename_ptr, functionname_ptr,
                                     line_ptr,
-                                    ABI_64_P (abfd) ? 8 : 0))
+                                    ABI_64_P (abfd) ? 8 : 0,
+                                    &elf_tdata (abfd)->dwarf2_find_line_info))
     return true;
 
   msec = bfd_get_section_by_name (abfd, ".mdebug");
@@ -3808,7 +3894,8 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
 
 /* MIPS ELF linker hash table.  */
 
-struct mips_elf_link_hash_table {
+struct mips_elf_link_hash_table
+{
   struct elf_link_hash_table root;
 #if 0
   /* We no longer use this.  */
@@ -3884,6 +3971,7 @@ mips_elf_link_hash_newfunc (entry, table, string)
       ret->esym.ifd = -2;
       ret->possibly_dynamic_relocs = 0;
       ret->min_dyn_reloc_index = 0;
+      ret->no_fn_stub = false;
       ret->fn_stub = NULL;
       ret->need_fn_stub = false;
       ret->call_stub = NULL;
@@ -4102,7 +4190,8 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 
 /* Structure used to pass information to mips_elf_output_extsym.  */
 
-struct extsym_info {
+struct extsym_info
+{
   bfd *abfd;
   struct bfd_link_info *info;
   struct ecoff_debug_info *debug;
@@ -4258,24 +4347,36 @@ mips_elf_output_extsym (h, data)
     }
   else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      /* Set type and value for a symbol with a function stub.  */
-      h->esym.asym.st = stProc;
-      sec = h->root.root.u.def.section;
-      if (sec == NULL)
-       h->esym.asym.value = 0;
-      else
+      struct mips_elf_link_hash_entry *hd = h;
+      boolean no_fn_stub = h->no_fn_stub;
+
+      while (hd->root.root.type == bfd_link_hash_indirect)
        {
-         output_section = sec->output_section;
-         if (output_section != NULL)
-           h->esym.asym.value = (h->root.plt.offset
-                                 + sec->output_offset
-                                 + output_section->vma);
-         else
-           h->esym.asym.value = 0;
+         hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
+         no_fn_stub = no_fn_stub || hd->no_fn_stub;
        }
+
+      if (!no_fn_stub)
+       {
+         /* Set type and value for a symbol with a function stub.  */
+         h->esym.asym.st = stProc;
+         sec = hd->root.root.u.def.section;
+         if (sec == NULL)
+           h->esym.asym.value = 0;
+         else
+           {
+             output_section = sec->output_section;
+             if (output_section != NULL)
+               h->esym.asym.value = (hd->root.plt.offset
+                                     + sec->output_offset
+                                     + output_section->vma);
+             else
+               h->esym.asym.value = 0;
+           }
 #if 0 /* FIXME?  */
-      h->esym.ifd = 0;
+         h->esym.ifd = 0;
 #endif
+       }
     }
 
   if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
@@ -4477,11 +4578,13 @@ _bfd_mips_elf_final_link (abfd, info)
   EXTR esym;
   bfd_vma last;
   unsigned int i;
-  static const char * const name[] = {
+  static const char * const name[] =
+  {
     ".text", ".init", ".fini", ".data",
     ".rodata", ".sdata", ".sbss", ".bss"
   };
-  static const int sc[] = {
+  static const int sc[] =
+  {
     scText, scInit, scFini, scData,
     scRData, scSData, scSBss, scBss
   };
@@ -5400,7 +5503,8 @@ mips_elf_record_global_got_symbol (h, info, g)
 /* This structure is passed to mips_elf_sort_hash_table_f when sorting
    the dynamic symbols.  */
 
-struct mips_elf_hash_sort_data {
+struct mips_elf_hash_sort_data
+{
   /* The symbol in the global GOT with the lowest dynamic symbol table
      index.  */
   struct elf_link_hash_entry *low;
@@ -5673,7 +5777,7 @@ mips_elf_next_relocation (r_type, relocation, relend)
 
 static boolean
 mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
-                                   symbol, addendp, input_section, local_p)
+                                   symbol, addendp, input_section)
      bfd *output_bfd;
      struct bfd_link_info *info;
      const Elf_Internal_Rela *rel;
@@ -5682,7 +5786,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
      bfd_vma symbol;
      bfd_vma *addendp;
      asection *input_section;
-     boolean local_p;
 {
   Elf_Internal_Rel outrel;
   boolean skip;
@@ -5767,15 +5870,16 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
          /* The relocation we're building is section-relative.
             Therefore, the original addend must be adjusted by the
             section offset.  */
-         *addendp += symbol - sec->output_section->vma;
+         *addendp += section_offset;
          /* Now, the relocation is just against the section.  */
          symbol = sec->output_section->vma;
        }
 
-      /* If the relocation is against a local symbol was previously an
-        absolute relocation, we must adjust it by the value we give
-        it in the dynamic symbol table.  */
-      if (local_p && r_type != R_MIPS_REL32)
+      /* If the relocation was previously an absolute relocation and
+        this symbol will not be referred to by the relocation, we must
+        adjust it by the value we give it in the dynamic symbol table.
+        Otherwise leave the job up to the dynamic linker.  */
+      if (!indx && r_type != R_MIPS_REL32)
        *addendp += symbol;
 
       /* The relocation is always an REL32 relocation because we don't
@@ -6150,7 +6254,7 @@ mips_elf_calculate_relocation (abfd,
                                 symbol + addend, sgot->contents + g);
            }
        }
-      else if (r_type == R_MIPS_GOT16)
+      else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
        /* There's no need to create a local GOT entry here; the
           calculation for a local GOT16 entry does not involve G.  */
        break;
@@ -6213,7 +6317,7 @@ mips_elf_calculate_relocation (abfd,
                                                   sec,
                                                   symbol,
                                                   &value,
-                                                  input_section, local_p))
+                                                  input_section))
            return false;
        }
       else
@@ -6245,14 +6349,14 @@ mips_elf_calculate_relocation (abfd,
       break;
 
     case R_MIPS16_26:
-      /* The calculation for R_MIPS_26 is just the same as for an
+      /* The calculation for R_MIPS16_26 is just the same as for an
         R_MIPS_26.  It's only the storage of the relocated field into
         the output file that's different.  That's handled in
         mips_elf_perform_relocation.  So, we just fall through to the
         R_MIPS_26 case here.  */
     case R_MIPS_26:
       if (local_p)
-       value = (((addend << 2) | (p & 0xf0000000)) + symbol) >> 2;
+       value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2;
       else
        value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2;
       value &= howto->dst_mask;
@@ -6318,6 +6422,7 @@ mips_elf_calculate_relocation (abfd,
       break;
 
     case R_MIPS_GOT16:
+    case R_MIPS_CALL16:
       if (local_p)
        {
          boolean forced;
@@ -6340,7 +6445,6 @@ mips_elf_calculate_relocation (abfd,
 
       /* Fall through.  */
 
-    case R_MIPS_CALL16:
     case R_MIPS_GOT_DISP:
       value = g;
       overflowed_p = mips_elf_overflow_p (value, 16);
@@ -6545,9 +6649,9 @@ mips_elf_perform_relocation (info, howto, relocation, value,
         ((sub1 << 16) | sub2)).
 
         When producing a relocateable object file, the calculation is
-        (((A < 2) | (P & 0xf0000000) + S) >> 2)
+        (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
         When producing a fully linked file, the calculation is
-        let R = (((A < 2) | (P & 0xf0000000) + S) >> 2)
+        let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
         ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)  */
 
       if (!info->relocateable)
@@ -6555,7 +6659,6 @@ mips_elf_perform_relocation (info, howto, relocation, value,
        value = (((value & 0x1f0000) << 5)
                 | ((value & 0x3e00000) >> 5)
                 | (value & 0xffff));
-
     }
   else if (r_type == R_MIPS16_GPREL)
     {
@@ -6678,6 +6781,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          REL relocation.  */
       boolean rela_relocation_p = true;
       int r_type = ELF32_R_TYPE (rel->r_info);
+      const char * msg = (const char *) NULL;
 
       /* Find the relocation howto for this relocation.  */
       if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
@@ -6932,8 +7036,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
 
        case bfd_reloc_notsupported:
-         abort ();
-         break;
+         msg = _("internal error: unsupported relocation error");
+         info->callbacks->warning
+           (info, msg, name, input_bfd, input_section, rel->r_offset);
+         return false;
 
        case bfd_reloc_overflow:
          if (use_saved_addend_p)
@@ -7654,10 +7760,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
             maximum number of pages needed by looking at the size of
-            the segment.  Similar comments apply to R_MIPS_GOT16.  We
-            don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because
-            these are always followed by an R_MIPS_GOT_LO16 or
-            R_MIPS_CALL_LO16.
+            the segment.  Similar comments apply to R_MIPS_GOT16 and
+            R_MIPS_CALL16.  We don't count R_MIPS_GOT_HI16, or
+            R_MIPS_CALL_HI16 because these are always followed by an
+            R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
 
             This estimation is very conservative since we can merge
             duplicate entries in the GOT.  In order to be less
@@ -7789,6 +7895,25 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
          break;
        }
 
+      /* We must not create a stub for a symbol that has relocations
+         related to taking the function's address.  */
+      switch (r_type)
+       {
+       default:
+         if (h != NULL)
+           {
+             struct mips_elf_link_hash_entry *mh;
+
+             mh = (struct mips_elf_link_hash_entry *) h;
+             mh->no_fn_stub = true;
+           }
+         break;
+       case R_MIPS_CALL16:
+       case R_MIPS_CALL_HI16:
+       case R_MIPS_CALL_LO16:
+         break;
+       }
+
       /* If this reloc is not a 16 bit call, and it has a global
          symbol, then we will need the fn_stub if there is one.
          References from a stub section do not count.  */
@@ -7924,6 +8049,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir, ind)
       || (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;
+  if (indmips->no_fn_stub)
+    dirmips->no_fn_stub = true;
 }
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
@@ -7964,8 +8091,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h)
     mips_elf_allocate_dynamic_relocations (dynobj,
                                           hmips->possibly_dynamic_relocs);
 
-  /* For a function, create a stub, if needed.  */
-  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+  /* For a function, create a stub, if allowed.  */
+  if (! hmips->no_fn_stub
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
       if (! elf_hash_table (info)->dynamic_sections_created)
        return true;
This page took 0.033351 seconds and 4 git commands to generate.