PC-rel fixes for x86-64 gas
Andreas Schwab
schwab@suse.de
Wed Mar 27 08:22:00 GMT 2002
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."
More information about the Binutils
mailing list