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]

.gpdword support, elf64-mips fixes


This patch implements .gpdword (thanks for the starting point, Eric!),
arranges for .cpadd to be usable in n32 and n64, and fixes a few
problems with gp-relative relocations that I ran into while playing
with it.  I have a patch for GCC that exercises these features, and I
couldn't figure out how to do multi-stage relocatable links of large
files, that would be necessary to test all of the problems this patch
fixes.  I hope this is still acceptable.

One of the problems was with GPREL32, that could no longer be
truncated to 32 bits when its value was actually being composed with a
_64 relocation (that's how the MIPS ELF64 ABI says 64-bit GPREL
relocations are supposed to be represented; eek! :-)

The other problems were in GPREL16 relocations, whose addends were
truncated to 16 bits even though they could be (and were!) wider than
that with RELA relocations.  Also, I had problems with symbols that
were forced local with linker scripts: we'd add gp0 to them even
though the original gp value hadn't been subtracted from their addends
in earlier relocatable links.

No regressions on mips-elf.  Ok to install?

Index: bfd/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* elfxx-mips.c (mips_elf_calculate_relocation): Take
	save_addend argument.  Don't apply the 32-bit mask to a
	GPREL32 value if it's to be used in another relocation.  Don't
	use forced-check computation of local_p to decide whether to
	add gp0 to GPREL16 value.  Don't use only the lowest 16 bits
	of the addend of a non-in-place GPREL16 relocation.
	(_bfd_mips_elf_relocate_section): Pass use_saved_addend_p to
	mips_elf_calculate_relocation().

Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.26
diff -u -p -r1.26 elfxx-mips.c
--- bfd/elfxx-mips.c 11 Oct 2002 08:33:11 -0000 1.26
+++ bfd/elfxx-mips.c 12 Oct 2002 05:27:58 -0000
@@ -345,7 +345,7 @@ static bfd_reloc_status_type mips_elf_ca
   PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
 	   const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
 	   Elf_Internal_Sym *, asection **, bfd_vma *, const char **,
-	   boolean *));
+	   boolean *, boolean));
 static bfd_vma mips_elf_obtain_contents
   PARAMS ((reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *));
 static boolean mips_elf_perform_relocation
@@ -2006,7 +2006,7 @@ static bfd_reloc_status_type
 mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
 			       relocation, addend, howto, local_syms,
 			       local_sections, valuep, namep,
-			       require_jalxp)
+			       require_jalxp, save_addend)
      bfd *abfd;
      bfd *input_bfd;
      asection *input_section;
@@ -2019,6 +2019,7 @@ mips_elf_calculate_relocation (abfd, inp
      bfd_vma *valuep;
      const char **namep;
      boolean *require_jalxp;
+     boolean save_addend;
 {
   /* The eventual value we will return.  */
   bfd_vma value;
@@ -2043,7 +2044,7 @@ mips_elf_calculate_relocation (abfd, inp
   struct mips_elf_link_hash_entry *h = NULL;
   /* True if the symbol referred to by this relocation is a local
      symbol.  */
-  boolean local_p;
+  boolean local_p, was_local_p;
   /* True if the symbol referred to by this relocation is "_gp_disp".  */
   boolean gp_disp_p = false;
   Elf_Internal_Shdr *symtab_hdr;
@@ -2071,6 +2072,7 @@ mips_elf_calculate_relocation (abfd, inp
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   local_p = mips_elf_local_relocation_p (input_bfd, relocation,
 					 local_sections, false);
+  was_local_p = local_p;
   if (! elf_bad_symtab (input_bfd))
     extsymoff = symtab_hdr->sh_info;
   else
@@ -2458,10 +2460,19 @@ mips_elf_calculate_relocation (abfd, inp
 	 order.  We don't need to do anything special here; the
 	 differences are handled in mips_elf_perform_relocation.  */
     case R_MIPS_GPREL16:
-      if (local_p)
-	value = mips_elf_sign_extend (addend, 16) + symbol + gp0 - gp;
-      else
-	value = mips_elf_sign_extend (addend, 16) + symbol - gp;
+      /* Only sign-extend the addend if it was extracted from the
+	 instruction.  If the addend was separate, leave it alone,
+	 otherwise we may lose significant bits.  */
+      if (howto->partial_inplace)
+	addend = mips_elf_sign_extend (addend, 16);
+      value = symbol + addend - gp;
+      /* If the symbol was local, any earlier relocatable links will
+	 have adjusted its addend with the gp offset, so compensate
+	 for that now.  Don't do it for symbols forced local in this
+	 link, though, since they won't have had the gp offset applied
+	 to them before.  */
+      if (was_local_p)
+	value += gp0;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -2494,7 +2505,9 @@ mips_elf_calculate_relocation (abfd, inp
       break;
 
     case R_MIPS_GPREL32:
-      value = (addend + symbol + gp0 - gp) & howto->dst_mask;
+      value = (addend + symbol + gp0 - gp);
+      if (!save_addend)
+	value &= howto->dst_mask;
       break;
 
     case R_MIPS_PC16:
@@ -5251,7 +5264,8 @@ _bfd_mips_elf_relocate_section (output_b
 					     input_section, info, rel,
 					     addend, howto, local_syms,
 					     local_sections, &value,
-					     &name, &require_jalx))
+					     &name, &require_jalx,
+					     use_saved_addend_p))
 	{
 	case bfd_reloc_continue:
 	  /* There's nothing to do.  */
Index: gas/ChangeLog
from  Eric Christopher  <echristo@redhat.com>, Alexandre Oliva  <aoliva@redhat.com>

	* config/tc-mips.c (s_gpdword): New function.
	(mips_pseudo_table): Add .gpdword.
	(mips_need_elf_addend_fixup): never for NEWABI.
	(md_apply_fix3): Don't mark BFD_RELOC64 after GPREL16 or
	GPREL32 as done.
	(s_cpadd): Generate .cpadd on NEWABI.

Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.172
diff -u -p -r1.172 tc-mips.c
--- gas/config/tc-mips.c 12 Oct 2002 05:23:32 -0000 1.172
+++ gas/config/tc-mips.c 12 Oct 2002 05:44:09 -0000
@@ -860,6 +860,7 @@ static void s_cprestore PARAMS ((int));
 static void s_cpreturn PARAMS ((int));
 static void s_gpvalue PARAMS ((int));
 static void s_gpword PARAMS ((int));
+static void s_gpdword PARAMS ((int));
 static void s_cpadd PARAMS ((int));
 static void s_insn PARAMS ((int));
 static void md_obj_begin PARAMS ((void));
@@ -961,6 +962,7 @@ static const pseudo_typeS mips_pseudo_ta
   {"cpreturn", s_cpreturn, 0},
   {"gpvalue", s_gpvalue, 0},
   {"gpword", s_gpword, 0},
+  {"gpdword", s_gpdword, 0},
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
 
@@ -11105,6 +11107,9 @@ md_apply_fix3 (fixP, valP, seg)
   /* We are not done if this is a composite relocation to set up gp.  */
   if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel
       && !(fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+	   || (fixP->fx_r_type == BFD_RELOC_64
+	       && (previous_fx_r_type == BFD_RELOC_GPREL32
+		   || previous_fx_r_type == BFD_RELOC_GPREL16))
 	   || (previous_fx_r_type == BFD_RELOC_MIPS_SUB
 	       && (fixP->fx_r_type == BFD_RELOC_HI16_S
 		   || fixP->fx_r_type == BFD_RELOC_LO16))))
@@ -12303,6 +12308,50 @@ s_gpword (ignore)
   demand_empty_rest_of_line ();
 }
 
+static void
+s_gpdword (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  symbolS *label;
+  expressionS ex;
+  char *p;
+
+  /* When not generating PIC code, this is treated as .dword.  */
+  if (mips_pic != SVR4_PIC)
+    {
+      s_cons (3);
+      return;
+    }
+
+  label = insn_labels != NULL ? insn_labels->label : NULL;
+  mips_emit_delays (true);
+  if (auto_align)
+    mips_align (3, 0, label);
+  mips_clear_insn_labels ();
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad (_("Unsupported use of .gpdword"));
+      ignore_rest_of_line ();
+    }
+
+  p = frag_more (8);
+  md_number_to_chars (p, (valueT) 0, 8);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, false,
+	       BFD_RELOC_GPREL32);
+
+  /* GPREL32 composed with 64 gives a 64-bit GP offset.  */
+  ex.X_op = O_absent;
+  ex.X_add_symbol = 0;
+  ex.X_add_number = 0;
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, false,
+	       BFD_RELOC_64);
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle the .cpadd pseudo-op.  This is used when dealing with switch
    tables in SVR4 PIC code.  */
 
@@ -12313,9 +12362,8 @@ s_cpadd (ignore)
   int icnt = 0;
   int reg;
 
-  /* This is ignored when not generating SVR4 PIC code or if this is NewABI
-     code.  */
-  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
+  /* This is ignored when not generating SVR4 PIC code.  */
+  if (mips_pic != SVR4_PIC)
     {
       s_ignore (0);
       return;
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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