* config/tc-ppc.c (md_apply_fix): Hoist code common to insn

and data fixups performing shift/high adjust/sign extension on
	fieldval.  Sink fx_pcrel handling and checks.  Use fixP->fx_size
	when writing data fixups rather than recalculating size.
This commit is contained in:
Alan Modra 2013-05-20 10:16:31 +00:00
parent 4d804846db
commit 5656a9815d
2 changed files with 168 additions and 189 deletions

View file

@ -1,3 +1,10 @@
2013-05-20 Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (md_apply_fix): Hoist code common to insn
and data fixups performing shift/high adjust/sign extension on
fieldval. Sink fx_pcrel handling and checks. Use fixP->fx_size
when writing data fixups rather than recalculating size.
2013-05-16 Jan-Benedict Glaw <jbglaw@lug-owl.de>
* doc/c-msp430.texi: Fix typo.

View file

@ -6287,6 +6287,8 @@ void
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
valueT value = * valP;
offsetT fieldval;
const struct powerpc_operand *operand;
#ifdef OBJ_ELF
if (fixP->fx_addsy != NULL)
@ -6325,16 +6327,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
}
operand = NULL;
if (fixP->fx_pcrel_adjust != 0)
{
/* Handle relocs in an insn. */
/* This is a fixup on an instruction. */
int opindex = fixP->fx_pcrel_adjust & 0xff;
const struct powerpc_operand *operand = &powerpc_operands[opindex];
char *where;
unsigned long insn;
offsetT fieldval;
operand = &powerpc_operands[opindex];
#ifdef OBJ_XCOFF
/* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol
does not generate a reloc. It uses the offset of `sym' within its
@ -6354,74 +6353,75 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
fixP->fx_done = 1;
}
#endif
fieldval = value;
}
/* Calculate value to be stored in field. */
fieldval = value;
switch (fixP->fx_r_type)
{
#ifdef OBJ_ELF
case BFD_RELOC_PPC64_ADDR16_LO_DS:
case BFD_RELOC_PPC_VLE_LO16A:
case BFD_RELOC_PPC_VLE_LO16D:
#endif
case BFD_RELOC_LO16:
case BFD_RELOC_LO16_PCREL:
fieldval = value & 0xffff;
sign_extend_16:
if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
fieldval = (fieldval ^ 0x8000) - 0x8000;
fixP->fx_no_overflow = 1;
break;
#ifdef OBJ_ELF
case BFD_RELOC_PPC_VLE_HI16A:
case BFD_RELOC_PPC_VLE_HI16D:
#endif
case BFD_RELOC_HI16:
case BFD_RELOC_HI16_PCREL:
fieldval = PPC_HI (value);
goto sign_extend_16;
#ifdef OBJ_ELF
case BFD_RELOC_PPC_VLE_HA16A:
case BFD_RELOC_PPC_VLE_HA16D:
#endif
case BFD_RELOC_HI16_S:
case BFD_RELOC_HI16_S_PCREL:
fieldval = PPC_HA (value);
goto sign_extend_16;
#ifdef OBJ_ELF
case BFD_RELOC_PPC64_HIGHER:
fieldval = PPC_HIGHER (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHER_S:
fieldval = PPC_HIGHERA (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHEST:
fieldval = PPC_HIGHEST (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHEST_S:
fieldval = PPC_HIGHESTA (value);
goto sign_extend_16;
#endif
default:
break;
}
if (operand != NULL)
{
/* Handle relocs in an insn. */
char *where;
unsigned long insn;
#ifdef OBJ_ELF
switch (fixP->fx_r_type)
{
#ifdef OBJ_ELF
case BFD_RELOC_PPC64_ADDR16_LO_DS:
if (fixP->fx_pcrel)
goto bad_pcrel;
/* fall through */
#endif
case BFD_RELOC_LO16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
/* fall through */
case BFD_RELOC_LO16_PCREL:
case BFD_RELOC_PPC_VLE_LO16A:
case BFD_RELOC_PPC_VLE_LO16D:
fieldval = value & 0xffff;
sign_extend_16:
if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
fieldval = (fieldval ^ 0x8000) - 0x8000;
fixP->fx_no_overflow = 1;
break;
case BFD_RELOC_HI16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
/* fall through */
case BFD_RELOC_HI16_PCREL:
case BFD_RELOC_PPC_VLE_HI16A:
case BFD_RELOC_PPC_VLE_HI16D:
fieldval = PPC_HI (value);
goto sign_extend_16;
case BFD_RELOC_HI16_S:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
/* fall through */
case BFD_RELOC_HI16_S_PCREL:
case BFD_RELOC_PPC_VLE_HA16A:
case BFD_RELOC_PPC_VLE_HA16D:
fieldval = PPC_HA (value);
goto sign_extend_16;
#ifdef OBJ_ELF
case BFD_RELOC_PPC64_HIGHER:
if (fixP->fx_pcrel)
goto bad_pcrel;
fieldval = PPC_HIGHER (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHER_S:
if (fixP->fx_pcrel)
goto bad_pcrel;
fieldval = PPC_HIGHERA (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHEST:
if (fixP->fx_pcrel)
goto bad_pcrel;
fieldval = PPC_HIGHEST (value);
goto sign_extend_16;
case BFD_RELOC_PPC64_HIGHEST_S:
if (fixP->fx_pcrel)
goto bad_pcrel;
fieldval = PPC_HIGHESTA (value);
goto sign_extend_16;
/* The following relocs can't be calculated by the assembler.
Leave the field zero. */
case BFD_RELOC_PPC_TPREL16:
@ -6463,8 +6463,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
gas_assert (fixP->fx_addsy != NULL);
S_SET_THREAD_LOCAL (fixP->fx_addsy);
fieldval = 0;
if (fixP->fx_pcrel)
goto bad_pcrel;
break;
/* These also should leave the field zero for the same
@ -6531,14 +6529,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_PPC_TLSGD:
case BFD_RELOC_PPC_TLSLD:
fieldval = 0;
if (fixP->fx_pcrel)
goto bad_pcrel;
break;
#endif
default:
break;
}
#endif
#ifdef OBJ_ELF
/* powerpc uses RELA style relocs, so if emitting a reloc the field
@ -6610,79 +6606,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
}
else
{
int size = 0;
offsetT fieldval = value;
/* Handle relocs in data. */
switch (fixP->fx_r_type)
{
case BFD_RELOC_CTOR:
if (ppc_obj64)
goto ctor64;
/* fall through */
case BFD_RELOC_32:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_32_PCREL;
/* fall through */
case BFD_RELOC_32_PCREL:
case BFD_RELOC_RVA:
size = 4;
break;
case BFD_RELOC_64:
ctor64:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_64_PCREL;
/* fall through */
case BFD_RELOC_64_PCREL:
size = 8;
break;
case BFD_RELOC_16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_16_PCREL;
/* fall through */
case BFD_RELOC_16_PCREL:
size = 2;
break;
case BFD_RELOC_8:
if (fixP->fx_pcrel)
{
#ifdef OBJ_ELF
bad_pcrel:
#endif
if (fixP->fx_addsy)
{
char *sfile;
unsigned int sline;
/* Use expr_symbol_where to see if this is an
expression symbol. */
if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unresolved expression that must"
" be resolved"));
else
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot emit PC relative %s relocation"
" against %s"),
bfd_get_reloc_code_name (fixP->fx_r_type),
S_GET_NAME (fixP->fx_addsy));
}
else
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unable to resolve expression"));
fixP->fx_done = 1;
}
else
size = 1;
break;
case BFD_RELOC_VTABLE_INHERIT:
if (fixP->fx_addsy
&& !S_IS_DEFINED (fixP->fx_addsy)
@ -6697,54 +6623,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
#ifdef OBJ_ELF
/* These can appear with @l etc. in data. */
case BFD_RELOC_LO16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
case BFD_RELOC_LO16_PCREL:
size = 2;
break;
case BFD_RELOC_HI16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
case BFD_RELOC_HI16_PCREL:
size = 2;
fieldval = PPC_HI (value);
break;
case BFD_RELOC_HI16_S:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
case BFD_RELOC_HI16_S_PCREL:
size = 2;
fieldval = PPC_HA (value);
break;
case BFD_RELOC_PPC64_HIGHER:
if (fixP->fx_pcrel)
goto bad_pcrel;
size = 2;
fieldval = PPC_HIGHER (value);
break;
case BFD_RELOC_PPC64_HIGHER_S:
if (fixP->fx_pcrel)
goto bad_pcrel;
size = 2;
fieldval = PPC_HIGHERA (value);
break;
case BFD_RELOC_PPC64_HIGHEST:
if (fixP->fx_pcrel)
goto bad_pcrel;
size = 2;
fieldval = PPC_HIGHEST (value);
break;
case BFD_RELOC_PPC64_HIGHEST_S:
if (fixP->fx_pcrel)
goto bad_pcrel;
size = 2;
fieldval = PPC_HIGHESTA (value);
break;
case BFD_RELOC_PPC_DTPMOD:
@ -6835,8 +6722,17 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
#ifdef OBJ_XCOFF
case BFD_RELOC_NONE:
break;
#endif
case BFD_RELOC_CTOR:
case BFD_RELOC_32:
case BFD_RELOC_32_PCREL:
case BFD_RELOC_RVA:
case BFD_RELOC_64:
case BFD_RELOC_64_PCREL:
case BFD_RELOC_16:
case BFD_RELOC_16_PCREL:
case BFD_RELOC_8:
break;
default:
fprintf (stderr,
@ -6845,9 +6741,85 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
abort ();
}
if (size && APPLY_RELOC)
if (fixP->fx_size && APPLY_RELOC)
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
fieldval, size);
fieldval, fixP->fx_size);
}
/* We are only able to convert some relocs to pc-relative. */
if (!fixP->fx_done && fixP->fx_pcrel)
{
switch (fixP->fx_r_type)
{
case BFD_RELOC_LO16:
fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
break;
case BFD_RELOC_HI16:
fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
break;
case BFD_RELOC_HI16_S:
fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
break;
case BFD_RELOC_64:
fixP->fx_r_type = BFD_RELOC_64_PCREL;
break;
case BFD_RELOC_32:
fixP->fx_r_type = BFD_RELOC_32_PCREL;
break;
case BFD_RELOC_16:
fixP->fx_r_type = BFD_RELOC_16_PCREL;
break;
/* Some of course are already pc-relative. */
case BFD_RELOC_LO16_PCREL:
case BFD_RELOC_HI16_PCREL:
case BFD_RELOC_HI16_S_PCREL:
case BFD_RELOC_64_PCREL:
case BFD_RELOC_32_PCREL:
case BFD_RELOC_16_PCREL:
case BFD_RELOC_PPC_B16:
case BFD_RELOC_PPC_B16_BRTAKEN:
case BFD_RELOC_PPC_B16_BRNTAKEN:
case BFD_RELOC_PPC_B26:
case BFD_RELOC_PPC_LOCAL24PC:
case BFD_RELOC_24_PLT_PCREL:
case BFD_RELOC_32_PLT_PCREL:
case BFD_RELOC_64_PLT_PCREL:
case BFD_RELOC_PPC_VLE_REL8:
case BFD_RELOC_PPC_VLE_REL15:
case BFD_RELOC_PPC_VLE_REL24:
break;
default:
if (fixP->fx_addsy)
{
char *sfile;
unsigned int sline;
/* Use expr_symbol_where to see if this is an
expression symbol. */
if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unresolved expression that must"
" be resolved"));
else
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot emit PC relative %s relocation"
" against %s"),
bfd_get_reloc_code_name (fixP->fx_r_type),
S_GET_NAME (fixP->fx_addsy));
}
else
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unable to resolve expression"));
fixP->fx_done = 1;
break;
}
}
#ifdef OBJ_ELF