* config/tc-xtensa.c (xg_apply_tentative_value): Rename to

xg_apply_fix_value and return a value to indicate success.
        (md_pcrel_from): Skip check of fx_done.  Return 0 if not PC-relative.
        (xtensa_force_relocation): Remove checks for VTABLE relocs.
        (xtensa_validate_fix_sub): New.
        (xtensa_fix_adjustable): Remove check for external or weak symbols.
        (tc_gen_reloc): Move code to handle difference of symbols and code to
        apply tentative fix values to ...
        (md_apply_fix3): ...here.  Enable standard overflow checks for simple
        8, 16, and 32 bit relocations.  Apply fixes for slot-specific
        relocations when linkrelax flag is not set.
        * config/tc-xtensa.h (xtensa_validate_fix_sub): Add prototype.
        (TC_FORCE_RELOCATION_SUB_SAME, TC_VALIDATE_FIX_SUB): Define.
This commit is contained in:
Bob Wilson 2005-03-17 21:49:47 +00:00
parent 06648491d7
commit 30f725a1cf
3 changed files with 178 additions and 189 deletions

View File

@ -1,3 +1,19 @@
2005-03-17 Bob Wilson <bob.wilson@acm.org>
* config/tc-xtensa.c (xg_apply_tentative_value): Rename to
xg_apply_fix_value and return a value to indicate success.
(md_pcrel_from): Skip check of fx_done. Return 0 if not PC-relative.
(xtensa_force_relocation): Remove checks for VTABLE relocs.
(xtensa_validate_fix_sub): New.
(xtensa_fix_adjustable): Remove check for external or weak symbols.
(tc_gen_reloc): Move code to handle difference of symbols and code to
apply tentative fix values to ...
(md_apply_fix3): ...here. Enable standard overflow checks for simple
8, 16, and 32 bit relocations. Apply fixes for slot-specific
relocations when linkrelax flag is not set.
* config/tc-xtensa.h (xtensa_validate_fix_sub): Add prototype.
(TC_FORCE_RELOCATION_SUB_SAME, TC_VALIDATE_FIX_SUB): Define.
2005-03-17 Jan Beulich <jbeulich@novell.com>
* config/tc-i386.c (i386_scale): Beautify error message.

View File

@ -4934,8 +4934,8 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
}
static void
xg_apply_tentative_value (fixS *fixP, valueT val)
static int
xg_apply_fix_value (fixS *fixP, valueT val)
{
xtensa_isa isa = xtensa_default_isa;
static xtensa_insnbuf insnbuf = NULL;
@ -4967,11 +4967,9 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
/* CONST16 immediates are not PC-relative, despite the fact that we
reuse the normal PC-relative operand relocations for the low part
of a CONST16 operand. The code in tc_gen_reloc does not decode
the opcodes so it is more convenient to detect this special case
here. */
of a CONST16 operand. */
if (opcode == xtensa_const16_opcode)
return;
return 0;
xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode,
get_relaxable_immed (opcode), val,
@ -4979,6 +4977,8 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf);
xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0);
return 1;
}
@ -5452,11 +5452,8 @@ md_pcrel_from (fixS *fixP)
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
bfd_boolean alt_reloc;
if (fixP->fx_done)
return addr;
if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND)
return addr;
return 0;
if (!insnbuf)
{
@ -5477,14 +5474,15 @@ md_pcrel_from (fixS *fixP)
xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
/* Check for "alternate" relocation (operand not specified). */
/* Check for "alternate" relocations (operand not specified). None
of the current uses for these are really PC-relative. */
if (alt_reloc || opcode == xtensa_const16_opcode)
{
if (opcode != xtensa_l32r_opcode
&& opcode != xtensa_const16_opcode)
as_fatal (_("invalid relocation for '%s' instruction"),
xtensa_opcode_name (isa, opcode));
return addr;
return 0;
}
opnum = get_relaxable_immed (opcode);
@ -5496,7 +5494,7 @@ md_pcrel_from (fixS *fixP)
fixP->fx_line,
_("invalid relocation for operand %d of '%s'"),
opnum, xtensa_opcode_name (isa, opcode));
return addr;
return 0;
}
return 0 - opnd_value;
}
@ -5508,7 +5506,8 @@ int
xtensa_force_relocation (fixS *fix)
{
switch (fix->fx_r_type)
{
{
case BFD_RELOC_XTENSA_ASM_EXPAND:
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
case BFD_RELOC_XTENSA_SLOT2_ALT:
@ -5524,8 +5523,6 @@ xtensa_force_relocation (fixS *fix)
case BFD_RELOC_XTENSA_SLOT12_ALT:
case BFD_RELOC_XTENSA_SLOT13_ALT:
case BFD_RELOC_XTENSA_SLOT14_ALT:
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
return 1;
default:
break;
@ -5539,6 +5536,33 @@ xtensa_force_relocation (fixS *fix)
}
/* TC_VALIDATE_FIX_SUB hook */
int
xtensa_validate_fix_sub (fixS *fix)
{
segT add_symbol_segment, sub_symbol_segment;
/* The difference of two symbols should be resolved by the assembler when
linkrelax is not set. If the linker may relax the section containing
the symbols, then an Xtensa DIFF relocation must be generated so that
the linker knows to adjust the difference value. */
if (!linkrelax || fix->fx_addsy == NULL)
return 0;
/* Make sure both symbols are in the same segment, and that segment is
"normal" and relaxable. If the segment is not "normal", then the
fix is not valid. If the segment is not "relaxable", then the fix
should have been handled earlier. */
add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
if (! SEG_NORMAL (add_symbol_segment) ||
! relaxable_section (add_symbol_segment))
return 0;
sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
return (sub_symbol_segment == add_symbol_segment);
}
/* NO_PSEUDO_DOT hook */
/* This function has nothing to do with pseudo dots, but this is the
@ -5586,49 +5610,134 @@ xtensa_fix_adjustable (fixS *fixP)
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
if (fixP->fx_addsy
&& (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
return 0;
return 1;
}
void
md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
{
if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
valueT val;
switch (fixP->fx_r_type)
{
char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
switch (fixP->fx_r_type)
case BFD_RELOC_32:
case BFD_RELOC_16:
case BFD_RELOC_8:
if (linkrelax && fixP->fx_subsy)
{
case BFD_RELOC_XTENSA_ASM_EXPAND:
fixP->fx_done = 1;
break;
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
break;
case BFD_RELOC_16:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
break;
case BFD_RELOC_32:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
break;
default:
break;
}
case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
as_bad (_("unhandled local relocation fix %s"),
bfd_get_reloc_code_name (fixP->fx_r_type));
break;
/* An offset is only allowed when it results from adjusting a
local symbol into a section-relative offset. If the offset
came from the original expression, tc_fix_adjustable will have
prevented the fix from being converted to a section-relative
form so that we can flag the error here. */
if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot represent subtraction with an offset"));
case BFD_RELOC_32:
case BFD_RELOC_16:
case BFD_RELOC_8:
/* The only one we support that isn't an instruction field. */
md_number_to_chars (fixpos, *valP, fixP->fx_size);
fixP->fx_done = 1;
break;
val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- S_GET_VALUE (fixP->fx_subsy));
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = 0;
break;
default:
as_bad (_("unhandled local relocation fix %s"),
bfd_get_reloc_code_name (fixP->fx_r_type));
/* The difference value gets written out, and the DIFF reloc
identifies the address of the subtracted symbol (i.e., the one
with the lowest address). */
*valP = val;
fixP->fx_offset -= val;
fixP->fx_subsy = NULL;
}
else if (! fixP->fx_addsy)
{
val = *valP;
fixP->fx_done = 1;
}
else
break;
md_number_to_chars (fixpos, val, fixP->fx_size);
fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
break;
case BFD_RELOC_XTENSA_SLOT0_OP:
case BFD_RELOC_XTENSA_SLOT1_OP:
case BFD_RELOC_XTENSA_SLOT2_OP:
case BFD_RELOC_XTENSA_SLOT3_OP:
case BFD_RELOC_XTENSA_SLOT4_OP:
case BFD_RELOC_XTENSA_SLOT5_OP:
case BFD_RELOC_XTENSA_SLOT6_OP:
case BFD_RELOC_XTENSA_SLOT7_OP:
case BFD_RELOC_XTENSA_SLOT8_OP:
case BFD_RELOC_XTENSA_SLOT9_OP:
case BFD_RELOC_XTENSA_SLOT10_OP:
case BFD_RELOC_XTENSA_SLOT11_OP:
case BFD_RELOC_XTENSA_SLOT12_OP:
case BFD_RELOC_XTENSA_SLOT13_OP:
case BFD_RELOC_XTENSA_SLOT14_OP:
if (linkrelax)
{
/* Write the tentative value of a PC-relative relocation to a
local symbol into the instruction. The value will be ignored
by the linker, and it makes the object file disassembly
readable when all branch targets are encoded in relocations. */
assert (fixP->fx_addsy);
if (S_GET_SEGMENT (fixP->fx_addsy) == seg && !fixP->fx_plt
&& !S_FORCE_RELOC (fixP->fx_addsy, 1))
{
val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- md_pcrel_from (fixP));
(void) xg_apply_fix_value (fixP, val);
}
}
else if (! fixP->fx_addsy)
{
val = *valP;
if (xg_apply_fix_value (fixP, val))
fixP->fx_done = 1;
}
break;
case BFD_RELOC_XTENSA_ASM_EXPAND:
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
case BFD_RELOC_XTENSA_SLOT2_ALT:
case BFD_RELOC_XTENSA_SLOT3_ALT:
case BFD_RELOC_XTENSA_SLOT4_ALT:
case BFD_RELOC_XTENSA_SLOT5_ALT:
case BFD_RELOC_XTENSA_SLOT6_ALT:
case BFD_RELOC_XTENSA_SLOT7_ALT:
case BFD_RELOC_XTENSA_SLOT8_ALT:
case BFD_RELOC_XTENSA_SLOT9_ALT:
case BFD_RELOC_XTENSA_SLOT10_ALT:
case BFD_RELOC_XTENSA_SLOT11_ALT:
case BFD_RELOC_XTENSA_SLOT12_ALT:
case BFD_RELOC_XTENSA_SLOT13_ALT:
case BFD_RELOC_XTENSA_SLOT14_ALT:
/* These all need to be resolved at link-time. Do nothing now. */
break;
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = 0;
break;
default:
as_bad (_("unhandled local relocation fix %s"),
bfd_get_reloc_code_name (fixP->fx_r_type));
}
}
@ -5687,10 +5796,9 @@ md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
format. */
arelent *
tc_gen_reloc (asection *section, fixS *fixp)
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *reloc;
bfd_boolean apply_tentative_value = FALSE;
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
@ -5701,128 +5809,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
They'd better have been fully resolved by this point. */
assert ((int) fixp->fx_r_type > 0);
if (linkrelax && fixp->fx_subsy
&& (fixp->fx_r_type == BFD_RELOC_8
|| fixp->fx_r_type == BFD_RELOC_16
|| fixp->fx_r_type == BFD_RELOC_32))
{
int diff_size = 0;
bfd_vma diff_value, diff_mask = 0;
switch (fixp->fx_r_type)
{
case BFD_RELOC_8:
fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
diff_size = 1;
diff_mask = 0xff;
break;
case BFD_RELOC_16:
fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
diff_size = 2;
diff_mask = 0xffff;
break;
case BFD_RELOC_32:
fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
diff_size = 4;
diff_mask = 0xffffffff;
break;
default:
break;
}
/* An offset is only allowed when it results from adjusting a local
symbol into a section-relative offset. If the offset came from the
original expression, tc_fix_adjustable will have prevented the fix
from being converted to a section-relative form so that we can flag
the error here. */
if (fixp->fx_offset != 0 && !symbol_section_p (fixp->fx_addsy))
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("cannot represent subtraction with an offset"));
free (reloc->sym_ptr_ptr);
free (reloc);
return NULL;
}
assert (S_GET_SEGMENT (fixp->fx_addsy)
== S_GET_SEGMENT (fixp->fx_subsy));
diff_value = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
- S_GET_VALUE (fixp->fx_subsy));
/* Check for overflow. */
if ((diff_value & ~diff_mask) != 0)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("value of %ld too large"), diff_value);
free (reloc->sym_ptr_ptr);
free (reloc);
return NULL;
}
md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
diff_value, diff_size);
reloc->addend = fixp->fx_offset - diff_value;
}
else
{
reloc->addend = fixp->fx_offset;
switch (fixp->fx_r_type)
{
case BFD_RELOC_XTENSA_SLOT0_OP:
case BFD_RELOC_XTENSA_SLOT1_OP:
case BFD_RELOC_XTENSA_SLOT2_OP:
case BFD_RELOC_XTENSA_SLOT3_OP:
case BFD_RELOC_XTENSA_SLOT4_OP:
case BFD_RELOC_XTENSA_SLOT5_OP:
case BFD_RELOC_XTENSA_SLOT6_OP:
case BFD_RELOC_XTENSA_SLOT7_OP:
case BFD_RELOC_XTENSA_SLOT8_OP:
case BFD_RELOC_XTENSA_SLOT9_OP:
case BFD_RELOC_XTENSA_SLOT10_OP:
case BFD_RELOC_XTENSA_SLOT11_OP:
case BFD_RELOC_XTENSA_SLOT12_OP:
case BFD_RELOC_XTENSA_SLOT13_OP:
case BFD_RELOC_XTENSA_SLOT14_OP:
/* As a special case, the immediate value for a CONST16 opcode
should not be applied, since this kind of relocation is
handled specially for CONST16 and is not really PC-relative.
Rather than decode the opcode here, just wait and handle it
in xg_apply_tentative_value. */
apply_tentative_value = TRUE;
break;
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
case BFD_RELOC_XTENSA_SLOT2_ALT:
case BFD_RELOC_XTENSA_SLOT3_ALT:
case BFD_RELOC_XTENSA_SLOT4_ALT:
case BFD_RELOC_XTENSA_SLOT5_ALT:
case BFD_RELOC_XTENSA_SLOT6_ALT:
case BFD_RELOC_XTENSA_SLOT7_ALT:
case BFD_RELOC_XTENSA_SLOT8_ALT:
case BFD_RELOC_XTENSA_SLOT9_ALT:
case BFD_RELOC_XTENSA_SLOT10_ALT:
case BFD_RELOC_XTENSA_SLOT11_ALT:
case BFD_RELOC_XTENSA_SLOT12_ALT:
case BFD_RELOC_XTENSA_SLOT13_ALT:
case BFD_RELOC_XTENSA_SLOT14_ALT:
case BFD_RELOC_XTENSA_ASM_EXPAND:
case BFD_RELOC_32:
case BFD_RELOC_XTENSA_PLT:
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
break;
case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
as_warn (_("emitting simplification relocation"));
break;
default:
as_warn (_("emitting unknown relocation"));
}
}
reloc->addend = fixp->fx_offset;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL)
@ -5839,24 +5826,6 @@ tc_gen_reloc (asection *section, fixS *fixp)
as_fatal (_("internal error? cannot generate `%s' relocation"),
bfd_get_reloc_code_name (fixp->fx_r_type));
/* Write the tentative value of a PC-relative relocation to a local symbol
into the instruction. The value will be ignored by the linker, and it
makes the object file disassembly readable when the linkrelax flag is
set and all branch targets are encoded in relocations. */
if (linkrelax && apply_tentative_value && fixp->fx_pcrel)
{
valueT val;
assert (fixp->fx_addsy);
if (S_GET_SEGMENT (fixp->fx_addsy) == section && !fixp->fx_plt
&& !S_FORCE_RELOC (fixp->fx_addsy, 1))
{
val = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
- md_pcrel_from (fixp));
xg_apply_tentative_value (fixp, val);
}
}
return reloc;
}

View File

@ -291,6 +291,7 @@ extern const char *xtensa_target_format (void);
extern void xtensa_init_fix_data (struct fix *);
extern void xtensa_frag_init (fragS *);
extern int xtensa_force_relocation (struct fix *);
extern int xtensa_validate_fix_sub (struct fix *);
extern void xtensa_frob_label (struct symbol *);
extern void xtensa_end (void);
extern void xtensa_post_relax_hook (void);
@ -314,6 +315,9 @@ extern char *xtensa_section_rename (char *);
#define TC_FRAG_TYPE struct xtensa_frag_type
#define TC_FRAG_INIT(frag) xtensa_frag_init (frag)
#define TC_FORCE_RELOCATION(fix) xtensa_force_relocation (fix)
#define TC_FORCE_RELOCATION_SUB_SAME(fix, seg) \
(! SEG_NORMAL (seg) || xtensa_force_relocation (fix))
#define TC_VALIDATE_FIX_SUB(fix) xtensa_validate_fix_sub (fix)
#define NO_PSEUDO_DOT xtensa_check_inside_bundle ()
#define tc_canonicalize_symbol_name(s) xtensa_section_rename (s)
#define tc_canonicalize_section_name(s) xtensa_section_rename (s)