* bfd-in.h (CONST_STRNCPY) : Delete.
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index c9862d4bd572ed4b98b8c72c100c94177083c718..d0116227c7bca186a9d6bef09d0221078124ee38 100644 (file)
 
 #include "hashtab.h"
 
-/* This structure is used to hold .got entries while estimating got
-   sizes.  */
+/* This structure is used to hold information about one GOT entry.
+   There are three types of entry:
+
+      (1) absolute addresses
+           (abfd == NULL)
+      (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
+           (abfd != NULL, symndx >= 0)
+      (3) global and forced-local symbols
+           (abfd != NULL, symndx == -1)
+
+   Type (3) entries are treated differently for different types of GOT.
+   In the "master" GOT -- i.e.  the one that describes every GOT
+   reference needed in the link -- the mips_got_entry is keyed on both
+   the symbol and the input bfd that references it.  If it turns out
+   that we need multiple GOTs, we can then use this information to
+   create separate GOTs for each input bfd.
+
+   However, we want each of these separate GOTs to have at most one
+   entry for a given symbol, so their type (3) entries are keyed only
+   on the symbol.  The input bfd given by the "abfd" field is somewhat
+   arbitrary in this case.
+
+   This means that when there are multiple GOTs, each GOT has a unique
+   mips_got_entry for every symbol within it.  We can therefore use the
+   mips_got_entry fields (tls_type and gotidx) to track the symbol's
+   GOT index.
+
+   However, if it turns out that we need only a single GOT, we continue
+   to use the master GOT to describe it.  There may therefore be several
+   mips_got_entries for the same symbol, each with a different input bfd.
+   We want to make sure that each symbol gets a unique GOT entry, so when
+   there's a single GOT, we use the symbol's hash entry, not the
+   mips_got_entry fields, to track a symbol's GOT index.  */
 struct mips_got_entry
 {
   /* The input bfd in which the symbol is defined.  */
@@ -304,6 +335,8 @@ struct mips_elf_link_hash_table
   bfd_vma plt_header_size;
   /* The size of a PLT entry in bytes (VxWorks only).  */
   bfd_vma plt_entry_size;
+  /* The size of a function stub entry in bytes.  */
+  bfd_vma function_stub_size;
 };
 
 #define TLS_RELOC_P(r_type) \
@@ -504,6 +537,11 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
   (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0)
 
+/* Whether the section is readonly.  */
+#define MIPS_ELF_READONLY_SECTION(sec) \
+  ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))                \
+   == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+
 /* The name of the stub section.  */
 #define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs"
 
@@ -587,20 +625,25 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_GOT_MAX_SIZE(INFO) (ELF_MIPS_GP_OFFSET (INFO) + 0x7fff)
 
 /* Instructions which appear in a stub.  */
-#define STUB_LW(abfd)                                          \
-  ((ABI_64_P (abfd)                                            \
-    ? 0xdf998010               /* ld t9,0x8010(gp) */          \
-    : 0x8f998010))              /* lw t9,0x8010(gp) */
-#define STUB_MOVE(abfd)                                         \
-   ((ABI_64_P (abfd)                                           \
-     ? 0x03e0782d              /* daddu t7,ra */               \
-     : 0x03e07821))            /* addu t7,ra */
-#define STUB_JALR 0x0320f809   /* jalr t9,ra */
-#define STUB_LI16(abfd)                                         \
-  ((ABI_64_P (abfd)                                            \
-   ? 0x64180000                        /* daddiu t8,zero,0 */          \
-   : 0x24180000))              /* addiu t8,zero,0 */
-#define MIPS_FUNCTION_STUB_SIZE (16)
+#define STUB_LW(abfd)                                                  \
+  ((ABI_64_P (abfd)                                                    \
+    ? 0xdf998010                               /* ld t9,0x8010(gp) */  \
+    : 0x8f998010))                             /* lw t9,0x8010(gp) */
+#define STUB_MOVE(abfd)                                                        \
+   ((ABI_64_P (abfd)                                                   \
+     ? 0x03e0782d                              /* daddu t7,ra */       \
+     : 0x03e07821))                            /* addu t7,ra */
+#define STUB_LUI(VAL) (0x3c180000 + (VAL))     /* lui t8,VAL */
+#define STUB_JALR 0x0320f809                   /* jalr t9,ra */
+#define STUB_ORI(VAL) (0x37180000 + (VAL))     /* ori t8,t8,VAL */
+#define STUB_LI16U(VAL) (0x34180000 + (VAL))   /* ori t8,zero,VAL unsigned */
+#define STUB_LI16S(abfd, VAL)                                          \
+   ((ABI_64_P (abfd)                                                   \
+    ? (0x64180000 + (VAL))     /* daddiu t8,zero,VAL sign extended */  \
+    : (0x24180000 + (VAL))))   /* addiu t8,zero,VAL sign extended */
+
+#define MIPS_FUNCTION_STUB_NORMAL_SIZE 16
+#define MIPS_FUNCTION_STUB_BIG_SIZE 20
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -795,13 +838,16 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
 bfd_boolean
 _bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
 {
-  struct _mips_elf_section_data *sdata;
-  bfd_size_type amt = sizeof (*sdata);
+  if (!sec->used_by_bfd)
+    {
+      struct _mips_elf_section_data *sdata;
+      bfd_size_type amt = sizeof (*sdata);
 
-  sdata = bfd_zalloc (abfd, amt);
-  if (sdata == NULL)
-    return FALSE;
-  sec->used_by_bfd = sdata;
+      sdata = bfd_zalloc (abfd, amt);
+      if (sdata == NULL)
+       return FALSE;
+      sec->used_by_bfd = sdata;
+    }
 
   return _bfd_elf_new_section_hook (abfd, sec);
 }
@@ -2371,8 +2417,16 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
     return MINUS_ONE;
 
   if (TLS_RELOC_P (r_type))
-    return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, r_type,
-                              info, h, value);
+    {
+      if (entry->symndx == -1 && g->next == NULL)
+       /* A type (3) entry in the single-GOT case.  We use the symbol's
+          hash table entry to track the index.  */
+       return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
+                                  r_type, info, h, value);
+      else
+       return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
+                                  r_type, info, h, value);
+    }
   else
     return entry->gotidx;
 }
@@ -3118,55 +3172,54 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
   return 1;
 }
 
-/* Set the TLS GOT index for the GOT entry in ENTRYP.  */
+/* Set the TLS GOT index for the GOT entry in ENTRYP.  ENTRYP's NEXT field
+   is null iff there is just a single GOT.  */
 
 static int
 mips_elf_initialize_tls_index (void **entryp, void *p)
 {
   struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
   struct mips_got_info *g = p;
+  bfd_vma next_index;
 
   /* We're only interested in TLS symbols.  */
   if (entry->tls_type == 0)
     return 1;
 
-  if (entry->symndx == -1)
+  next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
+
+  if (entry->symndx == -1 && g->next == NULL)
     {
-      /* There may be multiple mips_got_entry structs for a global variable
-        if there is just one GOT.  Just do this once.  */
-      if (g->next == NULL)
+      /* A type (3) got entry in the single-GOT case.  We use the symbol's
+        hash table entry to track its index.  */
+      if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+       return 1;
+      entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
+      entry->d.h->tls_got_offset = next_index;
+    }
+  else
+    {
+      if (entry->tls_type & GOT_TLS_LDM)
        {
-         if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+         /* There are separate mips_got_entry objects for each input bfd
+            that requires an LDM entry.  Make sure that all LDM entries in
+            a GOT resolve to the same index.  */
+         if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
            {
-             entry->gotidx = entry->d.h->tls_got_offset;
+             entry->gotidx = g->tls_ldm_offset;
              return 1;
            }
-         entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
-       }
-    }
-  else if (entry->tls_type & GOT_TLS_LDM)
-    {
-      /* Similarly, there may be multiple structs for the LDM entry.  */
-      if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
-       {
-         entry->gotidx = g->tls_ldm_offset;
-         return 1;
+         g->tls_ldm_offset = next_index;
        }
+      entry->gotidx = next_index;
     }
 
-  /* Initialize the GOT offset.  */
-  entry->gotidx = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
-  if (g->next == NULL && entry->symndx == -1)
-    entry->d.h->tls_got_offset = entry->gotidx;
-
+  /* Account for the entries we've just allocated.  */
   if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
     g->tls_assigned_gotno += 2;
   if (entry->tls_type & GOT_TLS_IE)
     g->tls_assigned_gotno += 1;
 
-  if (entry->tls_type & GOT_TLS_LDM)
-    g->tls_ldm_offset = entry->gotidx;
-
   return 1;
 }
 
@@ -3492,16 +3545,19 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
       g->local_gotno += assign + pages;
       assign = g->local_gotno + g->global_gotno + g->tls_gotno;
 
+      /* Take g out of the direct list, and push it onto the reversed
+        list that gg points to.  g->next is guaranteed to be nonnull after
+        this operation, as required by mips_elf_initialize_tls_index. */
+      gn = g->next;
+      g->next = gg->next;
+      gg->next = g;
+
       /* Set up any TLS entries.  We always place the TLS entries after
         all non-TLS entries.  */
       g->tls_assigned_gotno = g->local_gotno + g->global_gotno;
       htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
 
-      /* Take g out of the direct list, and push it onto the reversed
-        list that gg points to.  */
-      gn = g->next;
-      g->next = gg->next;
-      gg->next = g;
+      /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
       g = gn;
 
       /* Mark global symbols in every non-primary GOT as ineligible for
@@ -3527,9 +3583,12 @@ mips_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
                          const Elf_Internal_Rela *relocation,
                          const Elf_Internal_Rela *relend)
 {
+  unsigned long r_symndx = ELF_R_SYM (abfd, relocation->r_info);
+
   while (relocation < relend)
     {
-      if (ELF_R_TYPE (abfd, relocation->r_info) == r_type)
+      if (ELF_R_TYPE (abfd, relocation->r_info) == r_type
+         && ELF_R_SYM (abfd, relocation->r_info) == r_symndx)
        return relocation;
 
       ++relocation;
@@ -4019,6 +4078,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        }
 
       symbol = sec->output_section->vma + sec->output_offset;
+      /* The target is 16-bit, but the stub isn't.  */
+      target_is_16_bit_code_p = FALSE;
     }
   /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
      need to redirect the call to the stub.  */
@@ -4037,8 +4098,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
          sec = NULL;
          for (o = input_bfd->sections; o != NULL; o = o->next)
            {
-             if (strncmp (bfd_get_section_name (input_bfd, o),
-                          CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+             if (CONST_STRNEQ (bfd_get_section_name (input_bfd, o),
+                               CALL_FP_STUB))
                {
                  sec = h->call_fp_stub;
                  break;
@@ -4413,7 +4474,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_GNU_REL16_S2:
       value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p;
       overflowed_p = mips_elf_overflow_p (value, 18);
-      value = (value >> 2) & howto->dst_mask;
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
       break;
 
     case R_MIPS_GOT_HI16:
@@ -4628,9 +4690,9 @@ mips_elf_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
 {
   const char *name = bfd_get_section_name (abfd, section);
 
-  return (strncmp (name, FN_STUB, sizeof FN_STUB - 1) == 0
-         || strncmp (name, CALL_STUB, sizeof CALL_STUB - 1) == 0
-         || strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0);
+  return (CONST_STRNEQ (name, FN_STUB)
+         || CONST_STRNEQ (name, CALL_STUB)
+         || CONST_STRNEQ (name, CALL_FP_STUB));
 }
 \f
 /* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
@@ -4868,6 +4930,12 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
        }
     }
 
+  /* If we've written this relocation for a readonly section,
+     we need to set DF_TEXTREL again, so that we do not delete the
+     DT_TEXTREL tag.  */
+  if (MIPS_ELF_READONLY_SECTION (input_section))
+    info->flags |= DF_TEXTREL;
+
   return TRUE;
 }
 \f
@@ -4914,39 +4982,30 @@ _bfd_elf_mips_mach (flagword flags)
        default:
        case E_MIPS_ARCH_1:
          return bfd_mach_mips3000;
-         break;
 
        case E_MIPS_ARCH_2:
          return bfd_mach_mips6000;
-         break;
 
        case E_MIPS_ARCH_3:
          return bfd_mach_mips4000;
-         break;
 
        case E_MIPS_ARCH_4:
          return bfd_mach_mips8000;
-         break;
 
        case E_MIPS_ARCH_5:
          return bfd_mach_mips5;
-         break;
 
        case E_MIPS_ARCH_32:
          return bfd_mach_mipsisa32;
-         break;
 
        case E_MIPS_ARCH_64:
          return bfd_mach_mipsisa64;
-         break;
 
        case E_MIPS_ARCH_32R2:
          return bfd_mach_mipsisa32r2;
-         break;
 
        case E_MIPS_ARCH_64R2:
          return bfd_mach_mipsisa64r2;
-         break;
        }
     }
 
@@ -5036,6 +5095,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
       /* Common symbols less than the GP size are automatically
         treated as SHN_MIPS_SCOMMON symbols on IRIX5.  */
       if (asym->value > elf_gp_size (abfd)
+         || ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_TLS
          || IRIX_COMPAT (abfd) == ict_irix6)
        break;
       /* Fall through.  */
@@ -5347,7 +5407,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
        return FALSE;
       break;
     case SHT_MIPS_GPTAB:
-      if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) != 0)
+      if (! CONST_STRNEQ (name, ".gptab."))
        return FALSE;
       break;
     case SHT_MIPS_UCODE:
@@ -5370,7 +5430,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
        return FALSE;
       break;
     case SHT_MIPS_CONTENT:
-      if (strncmp (name, ".MIPS.content", sizeof ".MIPS.content" - 1) != 0)
+      if (! CONST_STRNEQ (name, ".MIPS.content"))
        return FALSE;
       break;
     case SHT_MIPS_OPTIONS:
@@ -5378,7 +5438,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
        return FALSE;
       break;
     case SHT_MIPS_DWARF:
-      if (strncmp (name, ".debug_", sizeof ".debug_" - 1) != 0)
+      if (! CONST_STRNEQ (name, ".debug_"))
        return FALSE;
       break;
     case SHT_MIPS_SYMBOL_LIB:
@@ -5386,9 +5446,8 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
        return FALSE;
       break;
     case SHT_MIPS_EVENTS:
-      if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) != 0
-         && strncmp (name, ".MIPS.post_rel",
-                     sizeof ".MIPS.post_rel" - 1) != 0)
+      if (! CONST_STRNEQ (name, ".MIPS.events")
+         && ! CONST_STRNEQ (name, ".MIPS.post_rel"))
        return FALSE;
       break;
     default:
@@ -5508,7 +5567,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     }
   else if (strcmp (name, ".conflict") == 0)
     hdr->sh_type = SHT_MIPS_CONFLICT;
-  else if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0)
+  else if (CONST_STRNEQ (name, ".gptab."))
     {
       hdr->sh_type = SHT_MIPS_GPTAB;
       hdr->sh_entsize = sizeof (Elf32_External_gptab);
@@ -5565,7 +5624,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_type = SHT_MIPS_IFACE;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
     }
-  else if (strncmp (name, ".MIPS.content", strlen (".MIPS.content")) == 0)
+  else if (CONST_STRNEQ (name, ".MIPS.content"))
     {
       hdr->sh_type = SHT_MIPS_CONTENT;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
@@ -5577,7 +5636,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_entsize = 1;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
     }
-  else if (strncmp (name, ".debug_", sizeof ".debug_" - 1) == 0)
+  else if (CONST_STRNEQ (name, ".debug_"))
     hdr->sh_type = SHT_MIPS_DWARF;
   else if (strcmp (name, ".MIPS.symlib") == 0)
     {
@@ -5585,9 +5644,8 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       /* The sh_link and sh_info fields are set in
          final_write_processing.  */
     }
-  else if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) == 0
-          || strncmp (name, ".MIPS.post_rel",
-                      sizeof ".MIPS.post_rel" - 1) == 0)
+  else if (CONST_STRNEQ (name, ".MIPS.events")
+          || CONST_STRNEQ (name, ".MIPS.post_rel"))
     {
       hdr->sh_type = SHT_MIPS_EVENTS;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
@@ -5676,6 +5734,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
       /* Common symbols less than the GP size are automatically
         treated as SHN_MIPS_SCOMMON symbols.  */
       if (sym->st_size > elf_gp_size (abfd)
+         || ELF_ST_TYPE (sym->st_info) == STT_TLS
          || IRIX_COMPAT (abfd) == ict_irix6)
        break;
       /* Fall through.  */
@@ -6057,7 +6116,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   /* Check for the mips16 stub sections.  */
 
   name = bfd_get_section_name (abfd, sec);
-  if (strncmp (name, FN_STUB, sizeof FN_STUB - 1) == 0)
+  if (CONST_STRNEQ (name, FN_STUB))
     {
       unsigned long r_symndx;
 
@@ -6082,12 +6141,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
-                 || strncmp (bfd_get_section_name (abfd, o), FN_STUB,
-                             sizeof FN_STUB - 1) == 0
-                 || strncmp (bfd_get_section_name (abfd, o), CALL_STUB,
-                             sizeof CALL_STUB - 1) == 0
-                 || strncmp (bfd_get_section_name (abfd, o), CALL_FP_STUB,
-                             sizeof CALL_FP_STUB - 1) == 0)
+                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), FN_STUB)
+                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), CALL_STUB)
+                 || CONST_STRNEQ (bfd_get_section_name (abfd, o), CALL_FP_STUB))
                continue;
 
              sec_relocs
@@ -6163,8 +6219,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
        }
     }
-  else if (strncmp (name, CALL_STUB, sizeof CALL_STUB - 1) == 0
-          || strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+  else if (CONST_STRNEQ (name, CALL_STUB)
+          || CONST_STRNEQ (name, CALL_FP_STUB))
     {
       unsigned long r_symndx;
       struct mips_elf_link_hash_entry *h;
@@ -6193,7 +6249,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       /* H is the symbol this stub is for.  */
 
-      if (strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+      if (CONST_STRNEQ (name, CALL_FP_STUB))
        loc = &h->call_fp_stub;
       else
        loc = &h->call_stub;
@@ -6472,15 +6528,13 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (sreloc == NULL)
                    return FALSE;
                }
-#define MIPS_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
              if (info->shared)
                {
                  /* When creating a shared object, we must copy these
                     reloc types into the output file as R_MIPS_REL32
                     relocs.  Make room for this reloc in .rel(a).dyn.  */
                  mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
-                 if ((sec->flags & MIPS_READONLY_SECTION)
-                     == MIPS_READONLY_SECTION)
+                 if (MIPS_ELF_READONLY_SECTION (sec))
                    /* We tell the dynamic linker that there are
                       relocations against the text segment.  */
                    info->flags |= DF_TEXTREL;
@@ -6493,8 +6547,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      defined in a dynamic object.  */
                  hmips = (struct mips_elf_link_hash_entry *) h;
                  ++hmips->possibly_dynamic_relocs;
-                 if ((sec->flags & MIPS_READONLY_SECTION)
-                     == MIPS_READONLY_SECTION)
+                 if (MIPS_ELF_READONLY_SECTION (sec))
                    /* We need it to tell the dynamic linker if there
                       are relocations against the text segment.  */
                    hmips->readonly_reloc = TRUE;
@@ -6581,12 +6634,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          References from a stub section do not count.  */
       if (h != NULL
          && r_type != R_MIPS16_26
-         && strncmp (bfd_get_section_name (abfd, sec), FN_STUB,
-                     sizeof FN_STUB - 1) != 0
-         && strncmp (bfd_get_section_name (abfd, sec), CALL_STUB,
-                     sizeof CALL_STUB - 1) != 0
-         && strncmp (bfd_get_section_name (abfd, sec), CALL_FP_STUB,
-                     sizeof CALL_FP_STUB - 1) != 0)
+         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), FN_STUB)
+         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), CALL_STUB)
+         && ! CONST_STRNEQ (bfd_get_section_name (abfd, sec), CALL_FP_STUB))
        {
          struct mips_elf_link_hash_entry *mh;
 
@@ -6781,7 +6831,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   bfd *dynobj;
   struct mips_elf_link_hash_entry *hmips;
   asection *s;
+  struct mips_elf_link_hash_table *htab;
 
+  htab = mips_elf_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
   /* Make sure we know what is going on here.  */
@@ -6834,7 +6886,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          h->plt.offset = s->size;
 
          /* Make room for this stub code.  */
-         s->size += MIPS_FUNCTION_STUB_SIZE;
+         s->size += htab->function_stub_size;
 
          /* The last half word of the stub will be filled with the index
             of this symbol in .dynsym section.  */
@@ -7022,6 +7074,32 @@ _bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info,
   return TRUE;
 }
 \f
+/* Return the number of dynamic section symbols required by OUTPUT_BFD.
+   The number might be exact or a worst-case estimate, depending on how
+   much information is available to elf_backend_omit_section_dynsym at
+   the current linking stage.  */
+
+static bfd_size_type
+count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
+{
+  bfd_size_type count;
+
+  count = 0;
+  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+    {
+      asection *p;
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (output_bfd);
+      for (p = output_bfd->sections; p ; p = p->next)
+       if ((p->flags & SEC_EXCLUDE) == 0
+           && (p->flags & SEC_ALLOC) != 0
+           && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
+         ++count;
+    }
+  return count;
+}
+
 /* This function is called after all the input files have been read,
    and the input sections have been assigned to output sections.  We
    check for any mips16 stub sections that we can discard.  */
@@ -7038,6 +7116,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
   int i;
   bfd_size_type loadable_size = 0;
   bfd_size_type local_gotno;
+  bfd_size_type dynsymcount;
   bfd *sub;
   struct mips_elf_count_tls_arg count_tls_arg;
   struct mips_elf_link_hash_table *htab;
@@ -7096,10 +7175,22 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
        relocations, then GLOBAL_GOTSYM will be NULL.  */
     i = 0;
 
+  /* Get a worst-case estimate of the number of dynamic symbols needed.
+     At this point, dynsymcount does not account for section symbols
+     and count_section_dynsyms may overestimate the number that will
+     be needed.  */
+  dynsymcount = (elf_hash_table (info)->dynsymcount
+                + count_section_dynsyms (output_bfd, info));
+
+  /* Determine the size of one stub entry.  */
+  htab->function_stub_size = (dynsymcount > 0x10000
+                             ? MIPS_FUNCTION_STUB_BIG_SIZE
+                             : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+
   /* In the worst case, we'll get one stub per dynamic symbol, plus
      one to account for the dummy entry at the end required by IRIX
      rld.  */
-  loadable_size += MIPS_FUNCTION_STUB_SIZE * (i + 1);
+  loadable_size += htab->function_stub_size * (i + 1);
 
   if (htab->is_vxworks)
     /* There's no need to allocate page entries for VxWorks; R_MIPS_GOT16
@@ -7193,7 +7284,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
-      if (strncmp (name, ".rel", 4) == 0)
+      if (CONST_STRNEQ (name, ".rel"))
        {
          if (s->size != 0)
            {
@@ -7245,7 +7336,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              mips_elf_allocate_dynamic_relocations (dynobj, info, count);
            }
        }
-      else if (!htab->is_vxworks && strncmp (name, ".got", 4) == 0)
+      else if (!htab->is_vxworks && CONST_STRNEQ (name, ".got"))
        {
          /* _bfd_mips_elf_always_size_sections() has already done
             most of the work, but some symbols may have been mapped
@@ -7316,21 +7407,21 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
        {
          /* IRIX rld assumes that the function stub isn't at the end
-            of .text section. So put a dummy. XXX  */
-         s->size += MIPS_FUNCTION_STUB_SIZE;
+            of .text section.  So put a dummy.  XXX  */
+         s->size += htab->function_stub_size;
        }
       else if (! info->shared
               && ! mips_elf_hash_table (info)->use_rld_obj_head
-              && strncmp (name, ".rld_map", 8) == 0)
+              && CONST_STRNEQ (name, ".rld_map"))
        {
-         /* We add a room for __rld_map. It will be filled in by the
+         /* We add a room for __rld_map.  It will be filled in by the
             rtld to contain a pointer to the _r_debug structure.  */
          s->size += 4;
        }
       else if (SGI_COMPAT (output_bfd)
-              && strncmp (name, ".compact_rel", 12) == 0)
+              && CONST_STRNEQ (name, ".compact_rel"))
        s->size += mips_elf_hash_table (info)->compact_rel_size;
-      else if (strncmp (name, ".init", 5) != 0
+      else if (! CONST_STRNEQ (name, ".init")
               && s != htab->sgotplt
               && s != htab->splt)
        {
@@ -7411,6 +7502,12 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
        {
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
            return FALSE;
+
+         /* Clear the DF_TEXTREL flag.  It will be set again if we
+            write out an actual text relocation; we may not, because
+            at this point we do not know whether e.g. any .eh_frame
+            absolute relocations have been converted to PC-relative.  */
+         info->flags &= ~DF_TEXTREL;
        }
 
       if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
@@ -7948,13 +8045,16 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   asection *sgot;
   struct mips_got_info *g, *gg;
   const char *name;
+  int idx;
+  struct mips_elf_link_hash_table *htab;
 
+  htab = mips_elf_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
   if (h->plt.offset != MINUS_ONE)
     {
       asection *s;
-      bfd_byte stub[MIPS_FUNCTION_STUB_SIZE];
+      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
 
       /* This symbol has a stub.  Set it up.  */
 
@@ -7964,18 +8064,42 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                   MIPS_ELF_STUB_SECTION_NAME (dynobj));
       BFD_ASSERT (s != NULL);
 
-      /* FIXME: Can h->dynindx be more than 64K?  */
-      if (h->dynindx & 0xffff0000)
+      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
+                  || (h->dynindx <= 0xffff));
+
+      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
+        sign extension at runtime in the stub, resulting in a negative
+        index value.  */
+      if (h->dynindx & ~0x7fffffff)
        return FALSE;
 
       /* Fill the stub.  */
-      bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub);
-      bfd_put_32 (output_bfd, STUB_MOVE (output_bfd), stub + 4);
-      bfd_put_32 (output_bfd, STUB_JALR, stub + 8);
-      bfd_put_32 (output_bfd, STUB_LI16 (output_bfd) + h->dynindx, stub + 12);
+      idx = 0;
+      bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx);
+      idx += 4;
+      bfd_put_32 (output_bfd, STUB_MOVE (output_bfd), stub + idx);
+      idx += 4;
+      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
+        {
+          bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff),
+                      stub + idx);
+          idx += 4;
+        }
+      bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+      idx += 4;
+
+      /* If a large stub is not required and sign extension is not a
+         problem, then use legacy code in the stub.  */
+      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
+       bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff), stub + idx);
+      else if (h->dynindx & ~0x7fff)
+        bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx);
+      else
+        bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
+                   stub + idx);
 
       BFD_ASSERT (h->plt.offset <= s->size);
-      memcpy (s->contents + h->plt.offset, stub, MIPS_FUNCTION_STUB_SIZE);
+      memcpy (s->contents + h->plt.offset, stub, htab->function_stub_size);
 
       /* Mark the symbol as undefined.  plt.offset != -1 occurs
         only for the referenced symbol.  */
@@ -8437,6 +8561,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       bfd_byte *b;
+      int dyn_to_skip = 0, dyn_skipped = 0;
 
       BFD_ASSERT (sdyn != NULL);
       BFD_ASSERT (g != NULL);
@@ -8591,15 +8716,44 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                + htab->srelplt->output_offset);
              break;
 
+           case DT_TEXTREL:
+             /* If we didn't need any text relocations after all, delete
+                the dynamic tag.  */
+             if (!(info->flags & DF_TEXTREL))
+               {
+                 dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+                 swap_out_p = FALSE;
+               }
+             break;
+
+           case DT_FLAGS:
+             /* If we didn't need any text relocations after all, clear
+                DF_TEXTREL from DT_FLAGS.  */
+             if (!(info->flags & DF_TEXTREL))
+               dyn.d_un.d_val &= ~DF_TEXTREL;
+             else
+               swap_out_p = FALSE;
+             break;
+
            default:
              swap_out_p = FALSE;
              break;
            }
 
-         if (swap_out_p)
+         if (swap_out_p || dyn_skipped)
            (*get_elf_backend_data (dynobj)->s->swap_dyn_out)
-             (dynobj, &dyn, b);
+             (dynobj, &dyn, b - dyn_skipped);
+
+         if (dyn_to_skip)
+           {
+             dyn_skipped += dyn_to_skip;
+             dyn_to_skip = 0;
+           }
        }
+
+      /* Wipe out any trailing entries if we shifted down a dynamic tag.  */
+      if (dyn_skipped > 0)
+       memset (b - dyn_skipped, 0, dyn_skipped);
     }
 
   if (sgot != NULL && sgot->size > 0)
@@ -8629,11 +8783,10 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
          MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000,
                             sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd));
        }
-    }
 
-  if (sgot != NULL)
-    elf_section_data (sgot->output_section)->this_hdr.sh_entsize
-      = MIPS_ELF_GOT_SIZE (output_bfd);
+      elf_section_data (sgot->output_section)->this_hdr.sh_entsize
+        = MIPS_ELF_GOT_SIZE (output_bfd);
+    }
 
   /* Generate dynamic relocations for the non-primary gots.  */
   if (gg != NULL && gg->next)
@@ -8748,10 +8901,10 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              {
                file_ptr dummy_offset;
 
-               BFD_ASSERT (s->size >= MIPS_FUNCTION_STUB_SIZE);
-               dummy_offset = s->size - MIPS_FUNCTION_STUB_SIZE;
+               BFD_ASSERT (s->size >= htab->function_stub_size);
+               dummy_offset = s->size - htab->function_stub_size;
                memset (s->contents + dummy_offset, 0,
-                       MIPS_FUNCTION_STUB_SIZE);
+                       htab->function_stub_size);
              }
          }
       }
@@ -8928,7 +9081,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
          name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
-                     && strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0);
+                     && CONST_STRNEQ (name, ".gptab."));
          sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
          BFD_ASSERT (sec != NULL);
          (*hdrpp)->sh_info = elf_section_data (sec)->this_idx;
@@ -8938,8 +9091,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
          name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
-                     && strncmp (name, ".MIPS.content",
-                                 sizeof ".MIPS.content" - 1) == 0);
+                     && CONST_STRNEQ (name, ".MIPS.content"));
          sec = bfd_get_section_by_name (abfd,
                                         name + sizeof ".MIPS.content" - 1);
          BFD_ASSERT (sec != NULL);
@@ -8959,13 +9111,12 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
          name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL);
-         if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) == 0)
+         if (CONST_STRNEQ (name, ".MIPS.events"))
            sec = bfd_get_section_by_name (abfd,
                                           name + sizeof ".MIPS.events" - 1);
          else
            {
-             BFD_ASSERT (strncmp (name, ".MIPS.post_rel",
-                                  sizeof ".MIPS.post_rel" - 1) == 0);
+             BFD_ASSERT (CONST_STRNEQ (name, ".MIPS.post_rel"));
              sec = bfd_get_section_by_name (abfd,
                                             (name
                                              + sizeof ".MIPS.post_rel" - 1));
@@ -8982,7 +9133,8 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
    segments.  */
 
 int
-_bfd_mips_elf_additional_program_headers (bfd *abfd)
+_bfd_mips_elf_additional_program_headers (bfd *abfd,
+                                         struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   asection *s;
   int ret = 0;
@@ -9073,15 +9225,18 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
                     || (*pm)->p_type == PT_INTERP))
            pm = &(*pm)->next;
 
-         amt = sizeof (struct elf_segment_map);
-         options_segment = bfd_zalloc (abfd, amt);
-         options_segment->next = *pm;
-         options_segment->p_type = PT_MIPS_OPTIONS;
-         options_segment->p_flags = PF_R;
-         options_segment->p_flags_valid = TRUE;
-         options_segment->count = 1;
-         options_segment->sections[0] = s;
-         *pm = options_segment;
+         if (*pm == NULL || (*pm)->p_type != PT_MIPS_OPTIONS)
+           {
+             amt = sizeof (struct elf_segment_map);
+             options_segment = bfd_zalloc (abfd, amt);
+             options_segment->next = *pm;
+             options_segment->p_type = PT_MIPS_OPTIONS;
+             options_segment->p_flags = PF_R;
+             options_segment->p_flags_valid = TRUE;
+             options_segment->count = 1;
+             options_segment->sections[0] = s;
+             *pm = options_segment;
+           }
        }
     }
   else
@@ -9345,7 +9500,7 @@ _bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj != NULL && force_local && h->root.type != STT_TLS
-      && (got = mips_elf_got_section (dynobj, FALSE)) != NULL
+      && (got = mips_elf_got_section (dynobj, TRUE)) != NULL
       && (g = mips_elf_section_data (got)->u.got_info) != NULL)
     {
       if (g->next)
@@ -9863,6 +10018,7 @@ _bfd_mips_elf_link_hash_table_create (bfd *abfd)
   ret->splt = NULL;
   ret->plt_header_size = 0;
   ret->plt_entry_size = 0;
+  ret->function_stub_size = 0;
 
   return &ret->root.root;
 }
@@ -9938,18 +10094,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         we count the sections after (possibly) removing the .options
         section above.  */
 
-      dynsecsymcount = 0;
-      if (info->shared)
-       {
-         asection * p;
-
-         for (p = abfd->sections; p ; p = p->next)
-           if ((p->flags & SEC_EXCLUDE) == 0
-               && (p->flags & SEC_ALLOC) != 0
-               && !(*bed->elf_backend_omit_section_dynsym) (abfd, info, p))
-             ++ dynsecsymcount;
-       }
-
+      dynsecsymcount = count_section_dynsyms (abfd, info);
       if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1))
        return FALSE;
 
@@ -10280,7 +10425,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          mdebug_sec = o;
        }
 
-      if (strncmp (o->name, ".gptab.", sizeof ".gptab." - 1) == 0)
+      if (CONST_STRNEQ (o->name, ".gptab."))
        {
          const char *subname;
          unsigned int c;
@@ -10700,7 +10845,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
        = elf_elfheader (ibfd)->e_ident[EI_CLASS];
 
       if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-         && bfd_get_arch_info (obfd)->the_default)
+         && (bfd_get_arch_info (obfd)->the_default
+             || mips_mach_extends_p (bfd_get_mach (obfd), 
+                                     bfd_get_mach (ibfd))))
        {
          if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
                                   bfd_get_mach (ibfd)))
@@ -10949,24 +11096,34 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 
 const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
 {
-  { ".lit4",   5,  0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { ".lit8",   5,  0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { ".mdebug", 7,  0, SHT_MIPS_DEBUG, 0 },
-  { ".sbss",   5, -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { ".sdata",  6, -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { ".ucode",  6,  0, SHT_MIPS_UCODE, 0 },
-  { NULL,      0,  0, 0,              0 }
+  { STRING_COMMA_LEN (".lit4"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".lit8"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".mdebug"), 0, SHT_MIPS_DEBUG, 0 },
+  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".ucode"),  0, SHT_MIPS_UCODE, 0 },
+  { NULL,                     0,  0, 0,              0 }
 };
 
-/* Ensure that the STO_OPTIONAL flag is copied into h->other,
-   even if this is not a defintion of the symbol.  */
+/* Merge non visibility st_other attributes.  Ensure that the
+   STO_OPTIONAL flag is copied into h->other, even if this is not a
+   definiton of the symbol.  */
 void
 _bfd_mips_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
                                      const Elf_Internal_Sym *isym,
                                      bfd_boolean definition,
                                      bfd_boolean dynamic ATTRIBUTE_UNUSED)
 {
-  if (! definition
+  if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
+    {
+      unsigned char other;
+
+      other = (definition ? isym->st_other : h->other);
+      other &= ~ELF_ST_VISIBILITY (-1);
+      h->other = other | ELF_ST_VISIBILITY (h->other);
+    }
+
+  if (!definition
       && ELF_MIPS_IS_OPTIONAL (isym->st_other))
     h->other |= STO_OPTIONAL;
 }
@@ -10978,3 +11135,11 @@ _bfd_mips_elf_ignore_undef_symbol (struct elf_link_hash_entry *h)
 {
   return ELF_MIPS_IS_OPTIONAL (h->other) ? TRUE : FALSE;
 }
+
+bfd_boolean
+_bfd_mips_elf_common_definition (Elf_Internal_Sym *sym)
+{
+  return (sym->st_shndx == SHN_COMMON
+         || sym->st_shndx == SHN_MIPS_ACOMMON
+         || sym->st_shndx == SHN_MIPS_SCOMMON);
+}
This page took 0.041203 seconds and 4 git commands to generate.