}
-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;
/* 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,
xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf);
xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0);
+
+ return 1;
}
\f
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)
{
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);
fixP->fx_line,
_("invalid relocation for operand %d of '%s'"),
opnum, xtensa_opcode_name (isa, opcode));
- return addr;
+ return 0;
}
return 0 - opnd_value;
}
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:
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;
}
+/* 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
|| 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;
+ case BFD_RELOC_32:
+ case BFD_RELOC_16:
+ case BFD_RELOC_8:
+ if (linkrelax && fixP->fx_subsy)
+ {
+ 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;
+ }
+
+ /* 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"));
- switch (fixP->fx_r_type)
+ val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+ - S_GET_VALUE (fixP->fx_subsy));
+
+ /* 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)
{
- case BFD_RELOC_XTENSA_ASM_EXPAND:
+ val = *valP;
fixP->fx_done = 1;
- break;
+ }
+ 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_ASM_SIMPLIFY:
- as_bad (_("unhandled local relocation fix %s"),
- bfd_get_reloc_code_name (fixP->fx_r_type));
- 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_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;
+ 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;
+ 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));
- }
+ default:
+ as_bad (_("unhandled local relocation fix %s"),
+ bfd_get_reloc_code_name (fixP->fx_r_type));
}
}
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 *));
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)
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;
}