This is the mail archive of the binutils@sources.redhat.com 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 alpha hidden undefweak ld tests


To fix the bug, the minimum change is in elf64_alpha_relocate_section.
There, we were applying RELATIVE relocs to the undefweak symbol, which
of course made the runtime value non-zero.

The elf64_alpha_calc_dynrel_sizes and elf64_alpha_size_rela_got_1 changes
fix up the relocation section sizes so that we don't wind up with extra
NONE relocations where the RELATIVE relocations would have gone.

The relax changes recognize that there are lots of ways to get at zero
without using a .got entry.  Since virtually all applications have at
least one undefweak call in crtbegin.o (_Jv_RegisterClasses), this seemed
worthwhile.


r~


        * elf64-alpha.c (elf64_alpha_relax_with_lituse): Relax jsr to
        undefweak to use zero register.  Call elf64_alpha_relax_got_load
        if not all uses removed.
        (elf64_alpha_relax_got_load): Relax undefweak to lda zero.
        (elf64_alpha_relax_section): Handle undefweak symbols.
        (elf64_alpha_calc_dynrel_sizes): Don't add relocs for undefweak.
        (elf64_alpha_size_rela_got_1): Likewise.
        (elf64_alpha_relocate_section): Likewise.

Index: elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.133
diff -u -p -d -r1.133 elf64-alpha.c
--- elf64-alpha.c	22 May 2005 22:07:31 -0000	1.133
+++ elf64-alpha.c	22 May 2005 22:09:36 -0000
@@ -1300,9 +1300,7 @@ elf64_alpha_relax_with_lituse (info, sym
 	  /* Extract the displacement from the instruction, sign-extending
 	     it if necessary, then test whether it is within 16 or 32 bits
 	     displacement from GP.  */
-	  insn_disp = insn & 0x0000ffff;
-	  if (insn_disp & 0x8000)
-	    insn_disp |= ~0xffff;  /* Negative: sign-extend.  */
+	  insn_disp = ((insn & 0xffff) ^ 0x8000) - 0x8000;
 
 	  xdisp = disp + insn_disp;
 	  fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000);
@@ -1371,6 +1369,19 @@ elf64_alpha_relax_with_lituse (info, sym
 	    bfd_vma optdest, org;
 	    bfd_signed_vma odisp;
 
+	    /* For undefined weak symbols, we're mostly interested in getting
+	       rid of the got entry whenever possible, so optimize this to a
+	       use of the zero register.  */
+	    if (info->h && info->h->root.root.type == bfd_link_hash_undefweak)
+	      {
+		insn |= 31 << 16;
+		bfd_put_32 (info->abfd, (bfd_vma) insn,
+			    info->contents + urel->r_offset);
+
+		info->changed_contents = TRUE;
+		break;
+	      }
+
 	    /* If not zero, place to jump without needing pv.  */
 	    optdest = elf64_alpha_relax_opt_call (info, symval);
 	    org = (info->sec->output_section->vma
@@ -1474,9 +1485,11 @@ elf64_alpha_relax_with_lituse (info, sym
 		      info->contents + irel->r_offset);
 	  info->changed_contents = TRUE;
 	}
-    }
 
-  return TRUE;
+      return TRUE;
+    }
+  else
+    return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL);
 }
 
 static bfd_vma
@@ -1583,7 +1596,25 @@ elf64_alpha_relax_got_load (info, symval
     return TRUE;
 
   if (r_type == R_ALPHA_LITERAL)
-    disp = symval - info->gp;
+    {
+      /* Look for nice constant addresses.  This includes the not-uncommon
+	 special case of 0 for undefweak symbols.  */
+      if ((info->h && info->h->root.root.type == bfd_link_hash_undefweak)
+	  || (!info->link_info->shared
+	      && (symval >= (bfd_vma)-0x8000 || symval < 0x8000)))
+	{
+	  disp = 0;
+	  insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
+	  insn |= (symval & 0xffff);
+	  r_type = R_ALPHA_NONE;
+	}
+      else
+	{
+	  disp = symval - info->gp;
+	  insn = (OP_LDA << 26) | (insn & 0x03ff0000);
+	  r_type = R_ALPHA_GPREL16;
+	}
+    }
   else
     {
       bfd_vma dtp_base, tp_base;
@@ -1592,17 +1623,26 @@ elf64_alpha_relax_got_load (info, symval
       dtp_base = alpha_get_dtprel_base (info->link_info);
       tp_base = alpha_get_tprel_base (info->link_info);
       disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
+
+      insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
+
+      switch (r_type)
+	{
+	case R_ALPHA_GOTDTPREL:
+	  r_type = R_ALPHA_DTPREL16;
+	  break;
+	case R_ALPHA_GOTTPREL:
+	  r_type = R_ALPHA_TPREL16;
+	  break;
+	default:
+	  BFD_ASSERT (0);
+	  return FALSE;
+	}
     }
 
   if (disp < -0x8000 || disp >= 0x8000)
     return TRUE;
 
-  /* Exchange LDQ for LDA.  In the case of the TLS relocs, we're loading
-     a constant, so force the base register to be $31.  */
-  if (r_type == R_ALPHA_LITERAL)
-    insn = (OP_LDA << 26) | (insn & 0x03ff0000);
-  else
-    insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
   bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
   info->changed_contents = TRUE;
 
@@ -1617,22 +1657,6 @@ elf64_alpha_relax_got_load (info, symval
     }
 
   /* Smash the existing GOT relocation for its 16-bit immediate pair.  */
-  switch (r_type)
-    {
-    case R_ALPHA_LITERAL:
-      r_type = R_ALPHA_GPREL16;
-      break;
-    case R_ALPHA_GOTDTPREL:
-      r_type = R_ALPHA_DTPREL16;
-      break;
-    case R_ALPHA_GOTTPREL:
-      r_type = R_ALPHA_TPREL16;
-      break;
-    default:
-      BFD_ASSERT (0);
-      return FALSE;
-    }
-
   irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type);
   info->changed_relocs = TRUE;
 
@@ -2103,13 +2127,17 @@ elf64_alpha_relax_section (abfd, sec, li
 	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
 
 	  /* If the symbol is undefined, we can't do anything with it.  */
-	  if (h->root.root.type == bfd_link_hash_undefweak
-	      || h->root.root.type == bfd_link_hash_undefined)
+	  if (h->root.root.type == bfd_link_hash_undefined)
 	    continue;
 
-	  /* If the symbol isn't defined in the current module, again
-	     we can't do anything.  */
-	  if (!h->root.def_regular)
+	  /* If the symbol isn't defined in the current module,
+	     again we can't do anything.  */
+	  if (h->root.root.type == bfd_link_hash_undefweak)
+	    {
+	      info.tsec = bfd_abs_section_ptr;
+	      symval = 0;
+	    }
+	  else if (!h->root.def_regular)
 	    {
 	      /* Except for TLSGD relocs, which can sometimes be
 		 relaxed to GOTTPREL relocs.  */
@@ -3860,9 +3888,14 @@ elf64_alpha_calc_dynrel_sizes (h, info)
   /* If the symbol is dynamic, we'll need all the relocations in their
      natural form.  If this is a shared object, and it has been forced
      local, we'll need the same number of RELATIVE relocations.  */
-
   dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
 
+  /* If the symbol is a hidden undefined weak, then we never have any
+     relocations.  Avoid the loop which may want to add RELATIVE relocs
+     based on info->shared.  */
+  if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
+    return TRUE;
+
   for (relent = h->reloc_entries; relent; relent = relent->next)
     {
       entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
@@ -3950,9 +3983,14 @@ elf64_alpha_size_rela_got_1 (h, info)
   /* If the symbol is dynamic, we'll need all the relocations in their
      natural form.  If this is a shared object, and it has been forced
      local, we'll need the same number of RELATIVE relocations.  */
-
   dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
 
+  /* If the symbol is a hidden undefined weak, then we never have any
+     relocations.  Avoid the loop which may want to add RELATIVE relocs
+     based on info->shared.  */
+  if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
+    return TRUE;
+
   entries = 0;
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
     if (gotent->use_count > 0)
@@ -4445,7 +4483,7 @@ elf64_alpha_relocate_section (output_bfd
 	      /* If the symbol has been forced local, output a
 		 RELATIVE reloc, otherwise it will be handled in
 		 finish_dynamic_symbol.  */
-	      if (info->shared && !dynamic_symbol_p)
+	      if (info->shared && !dynamic_symbol_p && !undef_weak_ref)
 		elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
 					 gotent->got_offset, 0,
 					 R_ALPHA_RELATIVE, value);
@@ -4617,7 +4655,8 @@ elf64_alpha_relocate_section (output_bfd
 	      }
 	    else if (info->shared
 		     && r_symndx != 0
-		     && (input_section->flags & SEC_ALLOC))
+		     && (input_section->flags & SEC_ALLOC)
+		     && !undef_weak_ref)
 	      {
 		if (r_type == R_ALPHA_REFLONG)
 		  {
@@ -4650,6 +4689,14 @@ elf64_alpha_relocate_section (output_bfd
                  input_bfd, h->root.root.root.string);
               ret_val = FALSE;
             }
+	  else if ((info->shared || info->pie) && undef_weak_ref)
+            {
+              (*_bfd_error_handler)
+                (_("%B: pc-relative relocation against undefined weak symbol %s"),
+                 input_bfd, h->root.root.root.string);
+              ret_val = FALSE;
+            }
+
 
 	  /* ??? .eh_frame references to discarded sections will be smashed
 	     to relocations against SHN_UNDEF.  The .eh_frame format allows


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