bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sun, 19 Sep 2010 10:52:17 +0000 (10:52 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sun, 19 Sep 2010 10:52:17 +0000 (10:52 +0000)
* elfxx-mips.c (mips_elf_link_hash_entry): Add got_only_for_calls.
(mips_elf_link_hash_newfunc): Initialize it.
(mips_elf_record_global_got_symbol): Add a for_call parameter.
(mips_elf_count_got_symbols): Check SYMBOL_CALLS_LOCAL rather
than SYMBOL_REFERENCES_LOCAL if the GOT entry is only used for calls.
Try to remove .got entries in favour of .got.plt entries on VxWorks.
(_bfd_mips_elf_check_relocs): Do not try to avoid allocating
a global GOT entry for VxWorks calls.  Update uses of
mips_elf_record_global_got_symbol.
(allocate_dynrelocs): Set got_only_for_calls to false if the GOT
entry is used for dynamic relocations.

bfd/ChangeLog
bfd/elfxx-mips.c

index 5778bd7e6e39a2f5c075ccdc5310301dbb2889ef..545c603eac2718e60225b508c9026ef9d5f52ac1 100644 (file)
@@ -1,3 +1,17 @@
+2010-09-19  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * elfxx-mips.c (mips_elf_link_hash_entry): Add got_only_for_calls.
+       (mips_elf_link_hash_newfunc): Initialize it.
+       (mips_elf_record_global_got_symbol): Add a for_call parameter.
+       (mips_elf_count_got_symbols): Check SYMBOL_CALLS_LOCAL rather
+       than SYMBOL_REFERENCES_LOCAL if the GOT entry is only used for calls.
+       Try to remove .got entries in favour of .got.plt entries on VxWorks.
+       (_bfd_mips_elf_check_relocs): Do not try to avoid allocating
+       a global GOT entry for VxWorks calls.  Update uses of
+       mips_elf_record_global_got_symbol.
+       (allocate_dynrelocs): Set got_only_for_calls to false if the GOT
+       entry is used for dynamic relocations.
+
 2010-09-19  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * elfxx-mips.c (mips_got_entry): Adjust commentary.
index 804a7d4a4e8832bcb6b88ddcafbcaa09fa256b40..1ee9289ff83d5f22d5425340ea3e6b6a9d679a24 100644 (file)
@@ -374,6 +374,11 @@ struct mips_elf_link_hash_entry
   /* The highest GGA_* value that satisfies all references to this symbol.  */
   unsigned int global_got_area : 2;
 
+  /* True if all GOT relocations against this symbol are for calls.  This is
+     a looser condition than no_fn_stub below, because there may be other
+     non-call non-GOT relocations against the symbol.  */
+  unsigned int got_only_for_calls : 1;
+
   /* True if one of the relocations described by possibly_dynamic_relocs
      is against a readonly section.  */
   unsigned int readonly_reloc : 1;
@@ -1073,6 +1078,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->call_fp_stub = NULL;
       ret->tls_type = GOT_NORMAL;
       ret->global_got_area = GGA_NONE;
+      ret->got_only_for_calls = TRUE;
       ret->readonly_reloc = FALSE;
       ret->has_static_relocs = FALSE;
       ret->no_fn_stub = FALSE;
@@ -3477,11 +3483,13 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
 
 /* If H is a symbol that needs a global GOT entry, but has a dynamic
    symbol table index lower than any we've seen to date, record it for
-   posterity.  */
+   posterity.  FOR_CALL is true if the caller is only interested in
+   using the GOT entry for calls.  */
 
 static bfd_boolean
 mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
                                   bfd *abfd, struct bfd_link_info *info,
+                                  bfd_boolean for_call,
                                   unsigned char tls_flag)
 {
   struct mips_elf_link_hash_table *htab;
@@ -3493,6 +3501,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
   BFD_ASSERT (htab != NULL);
 
   hmips = (struct mips_elf_link_hash_entry *) h;
+  if (!for_call)
+    hmips->got_only_for_calls = FALSE;
 
   /* A global symbol in the GOT must also be in the dynamic symbol
      table.  */
@@ -3856,10 +3866,12 @@ static int
 mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
 {
   struct bfd_link_info *info;
+  struct mips_elf_link_hash_table *htab;
   struct mips_got_info *g;
 
   info = (struct bfd_link_info *) data;
-  g = mips_elf_hash_table (info)->got_info;
+  htab = mips_elf_hash_table (info);
+  g = htab->got_info;
   if (h->global_got_area != GGA_NONE)
     {
       /* Make a final decision about whether the symbol belongs in the
@@ -3871,7 +3883,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
         Note that the former condition does not always imply the
         latter: symbols do not bind locally if they are completely
         undefined.  We'll report undefined symbols later if appropriate.  */
-      if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root))
+      if (h->root.dynindx == -1
+         || (h->got_only_for_calls
+             ? SYMBOL_CALLS_LOCAL (info, &h->root)
+             : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
        {
          /* The symbol belongs in the local GOT.  We no longer need this
             entry if it was only used for relocations; those relocations
@@ -3880,6 +3895,13 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
            g->local_gotno++;
          h->global_got_area = GGA_NONE;
        }
+      else if (htab->is_vxworks
+              && h->got_only_for_calls
+              && h->root.plt.offset != MINUS_ONE)
+       /* On VxWorks, calls can refer directly to the .got.plt entry;
+          they don't need entries in the regular GOT.  .got.plt entries
+          will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
+       h->global_got_area = GGA_NONE;
       else
        {
          g->global_gotno++;
@@ -7654,11 +7676,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_CALL_LO16:
          if (h != NULL)
            {
-             /* VxWorks call relocations point at the function's .got.plt
-                entry, which will be allocated by adjust_dynamic_symbol.
-                Otherwise, this symbol requires a global GOT entry.  */
-             if ((!htab->is_vxworks || h->forced_local)
-                 && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+             /* Make sure there is room in the regular GOT to hold the
+                function's address.  We may eliminate it in favour of
+                a .got.plt entry later; see mips_elf_count_got_symbols.  */
+             if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0))
                return FALSE;
 
              /* We need a stub, not a plt entry for the undefined
@@ -7718,7 +7739,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_MIPS_GOT_DISP:
-         if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+         if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+                                                      FALSE, 0))
            return FALSE;
          break;
 
@@ -7750,8 +7772,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  (struct mips_elf_link_hash_entry *) h;
                hmips->tls_type |= flag;
 
-               if (h && !mips_elf_record_global_got_symbol (h, abfd,
-                                                            info, flag))
+               if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+                                                            FALSE, flag))
                  return FALSE;
              }
            else
@@ -8154,8 +8176,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             VxWorks does not enforce the same mapping between the GOT
             and the symbol table, so the same requirement does not
             apply there.  */
-         if (!htab->is_vxworks && hmips->global_got_area > GGA_RELOC_ONLY)
-           hmips->global_got_area = GGA_RELOC_ONLY;
+         if (!htab->is_vxworks)
+           {
+             if (hmips->global_got_area > GGA_RELOC_ONLY)
+               hmips->global_got_area = GGA_RELOC_ONLY;
+             hmips->got_only_for_calls = FALSE;
+           }
 
          mips_elf_allocate_dynamic_relocations
            (dynobj, info, hmips->possibly_dynamic_relocs);