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]

PC-rel fixes for x86-64 gas


This fixes a bug in the handling of pc-relative relocations for x86-64.
The problem is that the adjustment done in tc_gen_reloc is only ok for
relocations in instructions, not for things like `.long foo-.'.

Approved in private by Jan Hubicka <jh@suse.cz>.  Checked into mainline
and branch (the latter is slightly different due to code reorganisations
in the mainline, so I'm posting two patches).

Andreas.

2002-03-27  Andreas Schwab  <schwab@suse.de>

	* config/tc-i386.c (output_jump): Set fx_pcrel_adjust to size of
	field for pc-relative fixups.
	(output_disp): Likewise.
	(md_estimate_size_before_relax): Likewise.
	(tc_gen_reloc): Subtract fx_pcrel_adjust instead of fx_size for
	pc-relative fixups in 64bit mode.

--- gas/config/tc-i386.c.~1.113.~	2002-03-11 10:55:12.000000000 +0100
+++ gas/config/tc-i386.c	2002-03-22 17:11:16.000000000 +0100
@@ -2972,6 +2972,7 @@
 {
   char *p;
   int size;
+  fixS *fixP;
 
   if (i.tm.opcode_modifier & JumpByte)
     {
@@ -3022,8 +3023,9 @@
   p = frag_more (1 + size);
   *p++ = i.tm.base_opcode;
 
-  fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-	       i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+  fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+		      i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+  fixP->fx_pcrel_adjust = size;
 }
 
 static void
@@ -3216,6 +3218,7 @@
 	      int size = 4;
 	      int sign = 0;
 	      int pcrel = (i.flags[n] & Operand_PCrel) != 0;
+	      fixS *fixP;
 
 	      /* The PC relative address is computed relative
 		 to the instruction boundary, so in case immediate
@@ -3255,9 +3258,11 @@
 		}
 
 	      p = frag_more (size);
-	      fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-			   i.op[n].disps, pcrel,
-			   reloc (size, pcrel, sign, i.reloc[n]));
+	      fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+				  i.op[n].disps, pcrel,
+				  reloc (size, pcrel, sign, i.reloc[n]));
+	      if (pcrel)
+		fixP->fx_pcrel_adjust = size;
 	    }
 	}
     }
@@ -4202,6 +4207,7 @@
       RELOC_ENUM reloc_type;
       unsigned char *opcode;
       int old_fr_fix;
+      fixS *fixP;
 
       if (fragP->fr_var != NO_RELOC)
 	reloc_type = fragP->fr_var;
@@ -4219,10 +4225,11 @@
 	  /* Make jmp (0xeb) a (d)word displacement jump.  */
 	  opcode[0] = 0xe9;
 	  fragP->fr_fix += size;
-	  fix_new (fragP, old_fr_fix, size,
-		   fragP->fr_symbol,
-		   fragP->fr_offset, 1,
-		   reloc_type);
+	  fixP = fix_new (fragP, old_fr_fix, size,
+			  fragP->fr_symbol,
+			  fragP->fr_offset, 1,
+			  reloc_type);
+	  fixP->fx_pcrel_adjust = size;
 	  break;
 
 	case COND_JUMP86:
@@ -4240,10 +4247,11 @@
 	      /* We added two extra opcode bytes, and have a two byte
 		 offset.  */
 	      fragP->fr_fix += 2 + 2;
-	      fix_new (fragP, old_fr_fix + 2, 2,
-		       fragP->fr_symbol,
-		       fragP->fr_offset, 1,
-		       reloc_type);
+	      fixP = fix_new (fragP, old_fr_fix + 2, 2,
+			      fragP->fr_symbol,
+			      fragP->fr_offset, 1,
+			      reloc_type);
+	      fixP->fx_pcrel_adjust = size;
 	      break;
 	    }
 	  /* Fall through.  */
@@ -4258,10 +4266,11 @@
 	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
 	  /* We've added an opcode byte.  */
 	  fragP->fr_fix += 1 + size;
-	  fix_new (fragP, old_fr_fix + 1, size,
-		   fragP->fr_symbol,
-		   fragP->fr_offset, 1,
-		   reloc_type);
+	  fixP = fix_new (fragP, old_fr_fix + 1, size,
+			  fragP->fr_symbol,
+			  fragP->fr_offset, 1,
+			  reloc_type);
+	  fixP->fx_pcrel_adjust = size;
 	  break;
 
 	default:
@@ -5105,7 +5114,7 @@
     {
       rel->addend = fixp->fx_offset;
       if (fixp->fx_pcrel)
-	rel->addend -= fixp->fx_size;
+	rel->addend -= fixp->fx_pcrel_adjust;
     }
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, code);
----------------------------------------------------------------------

2002-03-27  Andreas Schwab  <schwab@suse.de>

	* config/tc-i386.c (md_assemble): Set fx_pcrel_adjust to size of
	field for pc-relative fixups.
	(md_estimate_size_before_relax): Likewise.
	(tc_gen_reloc): Subtract fx_pcrel_adjust instead of fx_size for
	pc-relative fixups in 64bit mode.

--- gas/config/tc-i386.c.~1.108.2.2.~	2002-02-18 11:17:33.000000000 +0100
+++ gas/config/tc-i386.c	2002-03-27 16:32:07.000000000 +0100
@@ -2817,6 +2817,7 @@
     else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
       {
 	int size;
+	fixS *fixP;
 
 	if (i.tm.opcode_modifier & JumpByte)
 	  {
@@ -2867,8 +2868,9 @@
 	p = frag_more (1 + size);
 	*p++ = i.tm.base_opcode;
 
-	fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-		     i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+	fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+			    i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+	fixP->fx_pcrel_adjust = size;
       }
     else if (i.tm.opcode_modifier & JumpInterSegment)
       {
@@ -3024,6 +3026,7 @@
 			int size = 4;
 			int sign = 0;
 			int pcrel = (i.flags[n] & Operand_PCrel) != 0;
+			fixS *fixP;
 
 			/* The PC relative address is computed relative
 			   to the instruction boundary, so in case immediate
@@ -3063,9 +3066,11 @@
 			  }
 
 			p = frag_more (size);
-			fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-				     i.op[n].disps, pcrel,
-				     reloc (size, pcrel, sign, i.reloc[n]));
+			fixP = fix_new_exp (frag_now, p - frag_now->fr_literal,
+					    size, i.op[n].disps, pcrel,
+					    reloc (size, pcrel, sign, i.reloc[n]));
+			if (pcrel)
+			  fixP->fx_pcrel_adjust = size;
 		      }
 		  }
 	      }
@@ -4019,6 +4024,7 @@
       RELOC_ENUM reloc_type;
       unsigned char *opcode;
       int old_fr_fix;
+      fixS *fixP;
 
       if (fragP->fr_var != NO_RELOC)
 	reloc_type = fragP->fr_var;
@@ -4036,10 +4042,11 @@
 	  /* Make jmp (0xeb) a (d)word displacement jump.  */
 	  opcode[0] = 0xe9;
 	  fragP->fr_fix += size;
-	  fix_new (fragP, old_fr_fix, size,
-		   fragP->fr_symbol,
-		   fragP->fr_offset, 1,
-		   reloc_type);
+	  fixP = fix_new (fragP, old_fr_fix, size,
+			  fragP->fr_symbol,
+			  fragP->fr_offset, 1,
+			  reloc_type);
+	  fixP->fx_pcrel_adjust = size;
 	  break;
 
 	case COND_JUMP86:
@@ -4057,10 +4064,11 @@
 	      /* We added two extra opcode bytes, and have a two byte
 		 offset.  */
 	      fragP->fr_fix += 2 + 2;
-	      fix_new (fragP, old_fr_fix + 2, 2,
-		       fragP->fr_symbol,
-		       fragP->fr_offset, 1,
-		       reloc_type);
+	      fixP = fix_new (fragP, old_fr_fix + 2, 2,
+			      fragP->fr_symbol,
+			      fragP->fr_offset, 1,
+			      reloc_type);
+	      fixP->fx_pcrel_adjust = size;
 	      break;
 	    }
 	  /* Fall through.  */
@@ -4075,10 +4083,11 @@
 	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
 	  /* We've added an opcode byte.  */
 	  fragP->fr_fix += 1 + size;
-	  fix_new (fragP, old_fr_fix + 1, size,
-		   fragP->fr_symbol,
-		   fragP->fr_offset, 1,
-		   reloc_type);
+	  fixP = fix_new (fragP, old_fr_fix + 1, size,
+			  fragP->fr_symbol,
+			  fragP->fr_offset, 1,
+			  reloc_type);
+	  fixP->fx_pcrel_adjust = size;
 	  break;
 
 	default:
@@ -4920,7 +4929,7 @@
     {
       rel->addend = fixp->fx_offset;
       if (fixp->fx_pcrel)
-	rel->addend -= fixp->fx_size;
+	rel->addend -= fixp->fx_pcrel_adjust;
     }
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, code);

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE GmbH, Deutschherrnstr. 15-19, D-90429 Nürnberg
Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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