This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix handling of late forced-local calls on MIPS VxWorks


This patch fixes a failure in the MIPS vxworks-forced-local-1 test,
which I think must have initially passed by accident due to an overly
generous GOT size estimation.

VxWorks calls need normal GOT entries iff the target has no PLT, and the
test is making sure that we create such an entry if a symbol is forced
local late in the link process, such as via a version script.
As it stands, _bfd_mips_elf_check_relocs only allocates a GOT
entry for VxWorks calls if the symbol is already local at that stage:

	      /* 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))

But this is much too early to check.  We should instead allocate
a GOT entry unconditionally, and then try to remove it later if
it turns out that a .got.plt entry will do.

The patch below does this, and fixes the failure.  It adds a new
boolean to track whether all GOT references are for calls; this is
different from no_fn_stub on VxWorks, and although it might in
practice be the same as no_fn_stub on SVR4-based systems due
to the ABI's GOT/dynsym mapping, I still think it's worth separating.
The meaning of the new boolean is conceptually different from no_fn_stub
and its value is set at different times.

The new boolean also gives us a chance to make the right choice
between SYMBOL_REFERENCES_LOCAL and SYMBOL_CALLS_LOCAL in
mips_elf_count_got_symbols, as a minor optimisation.

Tested on mips-wrs-vxworks and mips64-linux-gnu (gcc as well
as binutils).  Applied.

Richard


bfd/
	* 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.

Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c	2010-09-19 11:25:47.000000000 +0100
+++ bfd/elfxx-mips.c	2010-09-19 11:36:48.000000000 +0100
@@ -374,6 +374,11 @@ #define GOT_TLS_DONE    0x80
   /* 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_h
       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_
 
 /* 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 (struc
   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 @@ mips_elf_resolve_final_got_entries (stru
 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_
 	 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_
 	    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, s
 	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, s
 	  /* 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, s
 		  (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
 	     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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]