diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 16 | ||||
-rw-r--r-- | gas/config/tc-xtensa.c | 343 | ||||
-rw-r--r-- | gas/config/tc-xtensa.h | 4 |
3 files changed, 176 insertions, 187 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 1610ac5..46ef21c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -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. diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index 9d20a6b..1eb6c42 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -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; + 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)); } } @@ -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; } diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h index 4743617..e38fa6c 100644 --- a/gas/config/tc-xtensa.h +++ b/gas/config/tc-xtensa.h @@ -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) |