X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fwrite.c;h=a67b34aee8a88b3ba06b83dc0ab7941d76c81f46;hb=80633e8e2a8be73fc3ce8ce5b2ae702d75e39b70;hp=6dd4ff1e725d93453f2b6dd797af6bcf07424a3a;hpb=f00f5ecd1dfe466c1a25dd50032f4f1f6d72b9f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/write.c b/gas/write.c index 6dd4ff1e72..a67b34aee8 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1,5 +1,5 @@ /* write.c - emit .o file - Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 1995 + Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -15,8 +15,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ /* This thing should be set up to do byteordering correctly. But... */ @@ -43,6 +44,14 @@ #define TC_FORCE_RELOCATION(FIXP) 0 #endif +#ifndef TC_FORCE_RELOCATION_SECTION +#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP) +#endif + +#ifndef MD_PCREL_FROM_SECTION +#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP) +#endif + #ifndef WORKING_DOT_WORD extern CONST int md_short_jump_size; extern CONST int md_long_jump_size; @@ -86,6 +95,8 @@ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE; #endif /* BFD_ASSEMBLER */ +static int n_fixups; + #ifdef BFD_ASSEMBLER static fixS *fix_new_internal PARAMS ((fragS *, int where, int size, symbolS *add, symbolS *sub, @@ -125,6 +136,8 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel, { fixS *fixP; + n_fixups++; + fixP = (fixS *) obstack_alloc (¬es, sizeof (fixS)); fixP->fx_frag = frag; @@ -150,6 +163,8 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel, fixP->fx_addnumber = 0; fixP->fx_tcbit = 0; fixP->fx_done = 0; + fixP->fx_no_overflow = 0; + fixP->fx_signed = 0; #ifdef TC_FIX_TYPE TC_INIT_FIX_DATA(fixP); @@ -235,7 +250,7 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type) symbolS *add = NULL; symbolS *sub = NULL; offsetT off = 0; - + switch (exp->X_op) { case O_absent: @@ -254,6 +269,21 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type) return fix_new_exp (frag, where, size, exp, pcrel, r_type); } + case O_symbol_rva: + add = exp->X_add_symbol; + off = exp->X_add_number; + +#if defined(BFD_ASSEMBLER) + r_type = BFD_RELOC_RVA; +#else +#if defined(TC_RVA_RELOC) + r_type = TC_RVA_RELOC; +#else + as_fatal("rva not supported"); +#endif +#endif + break; + case O_uminus: sub = exp->X_add_symbol; off = exp->X_add_number; @@ -268,9 +298,10 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type) case O_constant: off = exp->X_add_number; break; - + default: - as_bad ("expression too complex for fixup"); + add = make_expr_symbol (exp); + break; } return fix_new_internal (frag, where, size, add, sub, off, @@ -292,7 +323,7 @@ append (charPP, fromP, length) *charPP += length; } -#ifndef BFD_ASSEMBLER +#ifndef BFD_ASSEMBLER int section_alignment[SEG_MAXIMUM_ORDINAL]; #endif @@ -302,7 +333,7 @@ int section_alignment[SEG_MAXIMUM_ORDINAL]; * boundary, all of the other alignments within it will work. At * least one object format really uses this info. */ -void +void record_alignment (seg, align) /* Segment to which alignment pertains */ segT seg; @@ -355,6 +386,7 @@ chain_frchains_together_1 (section, frchp) { prev_frag->fr_next = frchp->frch_root; prev_frag = frchp->frch_last; + assert (prev_frag->fr_type != 0); #ifdef BFD_ASSEMBLER if (frchp->fix_root != (fixS *) NULL) { @@ -366,6 +398,7 @@ chain_frchains_together_1 (section, frchp) } #endif } + assert (prev_frag->fr_type != 0); prev_frag->fr_next = 0; return prev_frag; } @@ -398,7 +431,7 @@ chain_frchains_together (abfd, section, xxx) #if !defined (BFD) && !defined (BFD_ASSEMBLER) -void +void remove_subsegs (head, seg, root, last) frchainS *head; int seg; @@ -600,7 +633,7 @@ dump_section_relocs (abfd, sec, stream_) } } #else -#define dump_section_relocs(ABFD,SEC,STREAM) (void)(ABFD,SEC,STREAM) +#define dump_section_relocs(ABFD,SEC,STREAM) ((void) 0) #endif #ifndef EMIT_SECTION_SYMBOLS @@ -637,7 +670,27 @@ adjust_reloc_syms (abfd, sec, xxx) #endif sym = fixp->fx_addsy; - symsec = sym->bsym->section; + + /* All symbols should have already been resolved at this + point. It is possible to see unresolved expression + symbols, though, since they are not in the regular symbol + table. */ + if (sym != NULL && ! sym->sy_resolved) + resolve_symbol_value (sym); + if (fixp->fx_subsy != NULL && ! fixp->fx_subsy->sy_resolved) + resolve_symbol_value (fixp->fx_subsy); + + /* If this symbol is equated to an undefined symbol, convert + the fixup to being against that symbol. */ + if (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + { + fixp->fx_offset += sym->sy_value.X_add_number; + sym = sym->sy_value.X_add_symbol; + fixp->fx_addsy = sym; + } + + symsec = S_GET_SEGMENT (sym); if (sym != NULL && sym->sy_mri_common) { @@ -645,13 +698,27 @@ adjust_reloc_syms (abfd, sec, xxx) goto done; } + if (bfd_is_abs_section (symsec)) + { + /* The fixup_segment routine will not use this symbol in a + relocation unless TC_FORCE_RELOCATION returns 1. */ + if (TC_FORCE_RELOCATION (fixp)) + { + fixp->fx_addsy->sy_used_in_reloc = 1; +#ifdef UNDEFINED_DIFFERENCE_OK + if (fixp->fx_subsy != NULL) + fixp->fx_subsy->sy_used_in_reloc = 1; +#endif + } + goto done; + } + /* If it's one of these sections, assume the symbol is definitely going to be output. The code in md_estimate_size_before_relax in tc-mips.c uses this test as well, so if you change this code you should look at that code. */ if (bfd_is_und_section (symsec) - || bfd_is_abs_section (symsec) || bfd_is_com_section (symsec)) { fixp->fx_addsy->sy_used_in_reloc = 1; @@ -665,6 +732,40 @@ adjust_reloc_syms (abfd, sec, xxx) goto done; } + /* Don't try to reduce relocs which refer to .linkonce + sections. It can lead to confusion when a debugging + section refers to a .linkonce section. I hope this will + always be correct. */ + if (symsec != sec) + { + boolean linkonce; + + linkonce = false; +#ifdef BFD_ASSEMBLER + if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE) + != 0) + linkonce = true; +#endif +#ifdef OBJ_ELF + /* The GNU toolchain uses an extension for ELF: a section + beginning with the magic string .gnu.linkonce is a + linkonce section. */ + if (strncmp (segment_name (symsec), ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0) + linkonce = true; +#endif + + if (linkonce) + { + fixp->fx_addsy->sy_used_in_reloc = 1; +#ifdef UNDEFINED_DIFFERENCE_OK + if (fixp->fx_subsy != NULL) + fixp->fx_subsy->sy_used_in_reloc = 1; +#endif + goto done; + } + } + /* Since we're reducing to section symbols, don't attempt to reduce anything that's already using one. */ if (sym->bsym->flags & BSF_SECTION_SYM) @@ -684,7 +785,7 @@ adjust_reloc_syms (abfd, sec, xxx) #endif /* Is there some other (target cpu dependent) reason we can't adjust - this one? (E.g. relocations involving function addresses on + this one? (E.g. relocations involving function addresses on the PA. */ #ifdef tc_fix_adjustable if (! tc_fix_adjustable (fixp)) @@ -694,32 +795,15 @@ adjust_reloc_syms (abfd, sec, xxx) } #endif - /* For PIC support: We may get expressions like - "_GLOBAL_OFFSET_TABLE_+(.-L5)" where "." and "L5" may not - necessarily have had a fixed difference initially. But now - it should be a known constant, so we can reduce it. Since - we can't easily handle a symbol value that looks like - someUndefinedSymbol+const, though, we convert the fixup to - access the undefined symbol directly, and discard the - intermediate symbol. */ - if (S_GET_SEGMENT (sym) == expr_section - && sym->sy_value.X_op == O_add - && (resolve_symbol_value (sym->sy_value.X_add_symbol), - S_GET_SEGMENT (sym->sy_value.X_add_symbol) == undefined_section) - && (resolve_symbol_value (sym->sy_value.X_op_symbol), - S_GET_SEGMENT (sym->sy_value.X_op_symbol) == absolute_section)) - { - fixp->fx_offset += S_GET_VALUE (sym->sy_value.X_op_symbol); - fixp->fx_offset += sym->sy_value.X_add_number; - fixp->fx_addsy = sym->sy_value.X_add_symbol; - goto reduce_fixup; - } - /* If the section symbol isn't going to be output, the relocs at least should still work. If not, figure out what to do - when we run into that case. */ + when we run into that case. + + We refetch the segment when calling section_symbol, rather + than using symsec, because S_GET_VALUE may wind up changing + the section when it calls resolve_symbol_value. */ fixp->fx_offset += S_GET_VALUE (sym); - fixp->fx_addsy = section_symbol (symsec); + fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym)); fixp->fx_addsy->sy_used_in_reloc = 1; done: @@ -776,21 +860,46 @@ write_relocs (abfd, sec, xxx) { arelent *reloc; bfd_reloc_status_type s; + symbolS *sym; if (fixp->fx_done) { n--; continue; } + + /* If this is an undefined symbol which was equated to another + symbol, then use generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + { + symbolS *n; + + /* We must avoid looping, as that can occur with a badly + written program. */ + n = sym->sy_value.X_add_symbol; + if (n == sym) + break; + fixp->fx_offset += sym->sy_value.X_add_number; + sym = n; + } + fixp->fx_addsy = sym; + reloc = tc_gen_reloc (sec, fixp); if (!reloc) { n--; continue; } + +#if 0 + /* This test is triggered inappropriately for the SH. */ if (fixp->fx_where + fixp->fx_size > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) abort (); +#endif s = bfd_install_relocation (stdoutput, reloc, fixp->fx_frag->fr_literal, @@ -821,6 +930,7 @@ write_relocs (abfd, sec, xxx) arelent **reloc; char *data; bfd_reloc_status_type s; + symbolS *sym; int j; if (fixp->fx_done) @@ -828,6 +938,16 @@ write_relocs (abfd, sec, xxx) n--; continue; } + + /* If this is an undefined symbol which was equated to another + symbol, then use generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + sym = sym->sy_value.X_add_symbol; + fixp->fx_addsy = sym; + reloc = tc_gen_reloc (sec, fixp); for (j = 0; reloc[j]; j++) @@ -838,7 +958,8 @@ write_relocs (abfd, sec, xxx) data = fixp->fx_frag->fr_literal + fixp->fx_where; if (fixp->fx_where + fixp->fx_size > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) - abort (); + as_bad_where (fixp->fx_file, fixp->fx_line, + "internal error: fixup not contained within frag"); for (j = 0; reloc[j]; j++) { s = bfd_install_relocation (stdoutput, reloc[j], @@ -1163,7 +1284,7 @@ set_symtab () } #endif -void +void write_object_file () { struct frchain *frchainP; /* Track along all frchains. */ @@ -1360,7 +1481,7 @@ write_object_file () #else fix_new_exp (lie->frag, lie->word_goes_here - lie->frag->fr_literal, - 2, &exp, 0, BFD_RELOC_NONE); + 2, &exp, 0, BFD_RELOC_16); #endif #else #if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE) @@ -1571,6 +1692,13 @@ write_object_file () PROGRESS (1); +#ifdef tc_frob_file_before_adjust + tc_frob_file_before_adjust (); +#endif +#ifdef obj_frob_file_before_adjust + obj_frob_file_before_adjust (); +#endif + bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0); /* Set up symbol table, and write it out. */ @@ -1619,6 +1747,15 @@ write_object_file () resolve_symbol_value (symp); } + /* Skip symbols which were equated to undefined or common + symbols. */ + if (symp->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp))) + { + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + continue; + } + /* So far, common symbols have been treated like undefined symbols. Put them in the common section now. */ if (S_IS_DEFINED (symp) == 0 @@ -1680,6 +1817,9 @@ write_object_file () /* Now do any format-specific adjustments to the symbol table, such as adding file symbols. */ +#ifdef tc_adjust_symtab + tc_adjust_symtab (); +#endif #ifdef obj_adjust_symtab obj_adjust_symtab (); #endif @@ -1701,6 +1841,13 @@ write_object_file () bfd_map_over_sections (stdoutput, write_relocs, (char *) 0); +#ifdef tc_frob_file_after_relocs + tc_frob_file_after_relocs (); +#endif +#ifdef obj_frob_file_after_relocs + obj_frob_file_after_relocs (); +#endif + bfd_map_over_sections (stdoutput, write_contents, (char *) 0); #endif /* BFD_ASSEMBLER */ } @@ -1719,10 +1866,10 @@ write_object_file () * these frag addresses may not be the same as final object-file addresses. */ -#ifndef md_relax_frag +#ifdef TC_GENERIC_RELAX_TABLE /* Subroutines of relax_segment. */ -static int +static int is_dnrange (f1, f2) struct frag *f1; struct frag *f2; @@ -1733,7 +1880,111 @@ is_dnrange (f1, f2) return 0; } -#endif /* ! defined (md_relax_frag) */ +/* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE. */ + +long +relax_frag (fragP, stretch) + fragS *fragP; + long stretch; +{ + const relax_typeS *this_type; + const relax_typeS *start_type; + relax_substateT next_state; + relax_substateT this_state; + long aim, target, growth; + symbolS *symbolP = fragP->fr_symbol; + long offset = fragP->fr_offset; + /* Recompute was_address by undoing "+= stretch" done by relax_segment. */ + unsigned long was_address = fragP->fr_address - stretch; + unsigned long address = fragP->fr_address; + const relax_typeS *table = TC_GENERIC_RELAX_TABLE; + + this_state = fragP->fr_subtype; + start_type = this_type = table + this_state; + target = offset; + + if (symbolP) + { +#ifndef DIFF_EXPR_OK +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_BSS) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT)); +#endif + know (symbolP->sy_frag); +#endif + know (!(S_GET_SEGMENT (symbolP) == absolute_section) + || symbolP->sy_frag == &zero_address_frag); + target += + S_GET_VALUE (symbolP) + + symbolP->sy_frag->fr_address; + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. + + Beware zero-length frags. + + There should be a faster way to do this. */ + + if (symbolP->sy_frag->fr_address >= was_address + && is_dnrange (fragP, symbolP->sy_frag)) + { + target += stretch; + } + } + + aim = target - address - fragP->fr_fix; +#ifdef TC_PCREL_ADJUST + /* Currently only the ns32k family needs this */ + aim += TC_PCREL_ADJUST(fragP); +/*#else*/ + /* This machine doesn't want to use pcrel_adjust. + In that case, pcrel_adjust should be zero. */ +/* assert (fragP->fr_pcrel_adjust == 0);*/ +#endif +#ifdef md_prepare_relax_scan /* formerly called M68K_AIM_KLUDGE */ + md_prepare_relax_scan (fragP, address, aim, this_state, this_type); +#endif + + if (aim < 0) + { + /* Look backwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim >= this_type->rlx_backward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + else + { + /* Look forwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim <= this_type->rlx_forward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + + growth = this_type->rlx_length - start_type->rlx_length; + if (growth != 0) + fragP->fr_subtype = this_state; + return growth; +} + +#endif /* defined (TC_GENERIC_RELAX_TABLE) */ /* Relax_align. Advance location counter to next address that has 'alignment' lowest order bits all 0s, return size of adjustment made. */ @@ -1756,7 +2007,7 @@ relax_align (address, alignment) return (new_address - address); } -void +void relax_segment (segment_frag_root, segment) struct frag *segment_frag_root; segT segment; @@ -1838,8 +2089,6 @@ relax_segment (segment_frag_root, segment) unsigned long was_address; long offset; symbolS *symbolP; - long target; - long after; was_address = fragP->fr_address; address = fragP->fr_address += stretch; @@ -1924,44 +2173,50 @@ relax_segment (segment_frag_root, segment) break; case rs_org: - target = offset; + { + long target = offset; + long after; - if (symbolP) - { + if (symbolP) + { #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) - know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) - || (S_GET_SEGMENT (symbolP) == SEG_DATA) - || (S_GET_SEGMENT (symbolP) == SEG_TEXT) - || S_GET_SEGMENT (symbolP) == SEG_BSS); - know (symbolP->sy_frag); - know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) - || (symbolP->sy_frag == &zero_address_frag)); -#endif - target += S_GET_VALUE (symbolP) - + symbolP->sy_frag->fr_address; - } /* if we have a symbol */ - - know (fragP->fr_next); - after = fragP->fr_next->fr_address; - growth = target - after; - if (growth < 0) - { - /* Growth may be negative, but variable part of frag - cannot have fewer than 0 chars. That is, we can't - .org backwards. */ - as_bad ("attempt to .org backwards ignored"); - growth = 0; - } + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT) + || S_GET_SEGMENT (symbolP) == SEG_BSS); + know (symbolP->sy_frag); + know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (symbolP->sy_frag == &zero_address_frag)); +#endif + target += S_GET_VALUE (symbolP) + + symbolP->sy_frag->fr_address; + } /* if we have a symbol */ - growth -= stretch; /* This is an absolute growth factor */ - break; + know (fragP->fr_next); + after = fragP->fr_next->fr_address; + growth = target - after; + if (growth < 0) + { + /* Growth may be negative, but variable part of frag + cannot have fewer than 0 chars. That is, we can't + .org backwards. */ + as_bad ("attempt to .org backwards ignored"); + growth = 0; + } + + growth -= stretch; /* This is an absolute growth factor */ + break; + } case rs_space: if (symbolP) { growth = S_GET_VALUE (symbolP); - if (symbolP->sy_frag != &zero_address_frag) - as_bad (".space specifies non-absolute value"); + if (symbolP->sy_frag != &zero_address_frag + || S_IS_COMMON (symbolP) + || ! S_IS_DEFINED (symbolP)) + as_bad_where (fragP->fr_file, fragP->fr_line, + ".space specifies non-absolute value"); fragP->fr_symbol = 0; if (growth < 0) { @@ -1979,98 +2234,8 @@ relax_segment (segment_frag_root, segment) #else #ifdef TC_GENERIC_RELAX_TABLE /* The default way to relax a frag is to look through - md_relax_table. */ - { - const relax_typeS *this_type; - const relax_typeS *start_type; - relax_substateT next_state; - relax_substateT this_state; - long aim; - const relax_typeS *table = TC_GENERIC_RELAX_TABLE; - - this_state = fragP->fr_subtype; - start_type = this_type = table + this_state; - target = offset; - - if (symbolP) - { -#ifndef DIFF_EXPR_OK -#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) - know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) - || (S_GET_SEGMENT (symbolP) == SEG_DATA) - || (S_GET_SEGMENT (symbolP) == SEG_BSS) - || (S_GET_SEGMENT (symbolP) == SEG_TEXT)); -#endif - know (symbolP->sy_frag); -#endif - know (!(S_GET_SEGMENT (symbolP) == absolute_section) - || symbolP->sy_frag == &zero_address_frag); - target += - S_GET_VALUE (symbolP) - + symbolP->sy_frag->fr_address; - - /* If frag has yet to be reached on this pass, - assume it will move by STRETCH just as we did. - If this is not so, it will be because some frag - between grows, and that will force another pass. - - Beware zero-length frags. - - There should be a faster way to do this. */ - - if (symbolP->sy_frag->fr_address >= was_address - && is_dnrange (fragP, symbolP->sy_frag)) - { - target += stretch; - } - } - - aim = target - address - fragP->fr_fix; -#ifdef TC_PCREL_ADJUST - /* Currently only the ns32k family needs this */ - aim += TC_PCREL_ADJUST(fragP); -#else - /* This machine doesn't want to use pcrel_adjust. - In that case, pcrel_adjust should be zero. */ - assert (fragP->fr_pcrel_adjust == 0); -#endif - - if (aim < 0) - { - /* Look backwards. */ - for (next_state = this_type->rlx_more; next_state;) - if (aim >= this_type->rlx_backward) - next_state = 0; - else - { - /* Grow to next state. */ - this_state = next_state; - this_type = table + this_state; - next_state = this_type->rlx_more; - } - } - else - { -#ifdef M68K_AIM_KLUDGE - M68K_AIM_KLUDGE (aim, this_state, this_type); -#endif - /* Look forwards. */ - for (next_state = this_type->rlx_more; next_state;) - if (aim <= this_type->rlx_forward) - next_state = 0; - else - { - /* Grow to next state. */ - this_state = next_state; - this_type = table + this_state; - next_state = this_type->rlx_more; - } - } - - growth = this_type->rlx_length - start_type->rlx_length; - if (growth != 0) - fragP->fr_subtype = this_state; - } + TC_GENERIC_RELAX_TABLE. */ + growth = relax_frag (fragP, stretch); #endif /* TC_GENERIC_RELAX_TABLE */ #endif break; @@ -2131,7 +2296,7 @@ fixup_segment (fixP, this_segment_type) int pcrel, plt; fragS *fragP; segT add_symbol_segment = absolute_section; - + /* If the linker is doing the relaxing, we must not do any fixups. Well, strictly speaking that's not true -- we could do any that are @@ -2179,15 +2344,25 @@ fixup_segment (fixP, this_segment_type) if (add_symbolP) add_symbol_segment = S_GET_SEGMENT (add_symbolP); - + if (sub_symbolP) { resolve_symbol_value (sub_symbolP); - if (!add_symbolP) + if (add_symbolP == NULL || add_symbol_segment == absolute_section) { - /* Its just -sym */ + if (add_symbolP != NULL) + { + add_number += S_GET_VALUE (add_symbolP); + add_symbolP = NULL; + fixP->fx_addsy = NULL; + } + + /* It's just -sym */ if (S_GET_SEGMENT (sub_symbolP) == absolute_section) - add_number -= S_GET_VALUE (sub_symbolP); + { + add_number -= S_GET_VALUE (sub_symbolP); + fixP->fx_subsy = NULL; + } else if (pcrel && S_GET_SEGMENT (sub_symbolP) == this_segment_type) { @@ -2200,9 +2375,8 @@ fixup_segment (fixP, this_segment_type) "Negative of non-absolute symbol %s", S_GET_NAME (sub_symbolP)); } - else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment) - && (SEG_NORMAL (add_symbol_segment) - || (add_symbol_segment == absolute_section))) + else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment + && SEG_NORMAL (add_symbol_segment)) { /* Difference of 2 symbols from same segment. Can't make difference of 2 undefineds: 'value' means @@ -2223,10 +2397,11 @@ fixup_segment (fixP, this_segment_type) /* Let the target machine make the final determination as to whether or not a relocation will be needed to handle this fixup. */ - if (!TC_FORCE_RELOCATION (fixP)) + if (!TC_FORCE_RELOCATION_SECTION (fixP, this_segment_type)) { fixP->fx_pcrel = 0; fixP->fx_addsy = NULL; + fixP->fx_subsy = NULL; } } else @@ -2248,7 +2423,7 @@ fixup_segment (fixP, this_segment_type) ) { /* Make it pc-relative. */ - add_number += (md_pcrel_from (fixP) + add_number += (MD_PCREL_FROM_SECTION (fixP, this_segment_type) - S_GET_VALUE (sub_symbolP)); pcrel = 1; fixP->fx_pcrel = 1; @@ -2304,9 +2479,9 @@ fixup_segment (fixP, this_segment_type) #endif /* TC_I960 */ add_number += S_GET_VALUE (add_symbolP); - add_number -= md_pcrel_from (fixP); + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type); pcrel = 0; /* Lie. Don't want further pcrel processing. */ - + /* Let the target machine make the final determination as to whether or not a relocation will be needed to handle this fixup. */ @@ -2318,7 +2493,8 @@ fixup_segment (fixP, this_segment_type) } else { - if (add_symbol_segment == absolute_section) + if (add_symbol_segment == absolute_section + && ! pcrel) { #ifdef TC_I960 /* See comment about reloc_callj() above. */ @@ -2329,7 +2505,7 @@ fixup_segment (fixP, this_segment_type) /* Let the target machine make the final determination as to whether or not a relocation will be needed to handle this fixup. */ - + if (!TC_FORCE_RELOCATION (fixP)) { fixP->fx_addsy = NULL; @@ -2357,7 +2533,7 @@ fixup_segment (fixP, this_segment_type) continue; } /* COBR */ #endif /* TC_I960 */ - + #ifdef OBJ_COFF #ifdef TE_I386AIX if (S_IS_COMMON (add_symbolP)) @@ -2369,8 +2545,16 @@ fixup_segment (fixP, this_segment_type) else { seg_reloc_count++; +/* start-sanitize-v850 */ +#if !(defined (TC_V850) && defined (OBJ_ELF)) +/* end-sanitize-v850 */ +#if !(defined (TC_M68K) && defined (OBJ_ELF)) #if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF)) add_number += S_GET_VALUE (add_symbolP); +/* start-sanitize-v850 */ +#endif +/* end-sanitize-v850 */ +#endif #endif } } @@ -2378,7 +2562,7 @@ fixup_segment (fixP, this_segment_type) if (pcrel) { - add_number -= md_pcrel_from (fixP); + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type); if (add_symbolP == 0) { #ifndef BFD_ASSEMBLER @@ -2393,10 +2577,12 @@ fixup_segment (fixP, this_segment_type) if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0) { - valueT mask = 0; - if (size < sizeof (mask)) + if (size < sizeof (valueT)) { + valueT mask, hibit; + /* set all bits to one */ + mask = 0; mask--; /* Technically, combining these produces an undefined result if size is sizeof (valueT), though I think these two @@ -2405,8 +2591,12 @@ fixup_segment (fixP, this_segment_type) the host architecture. */ mask <<= size * 4; mask <<= size * 4; - if ((add_number & mask) != 0 - && (add_number & mask) != mask) + hibit = (valueT) 1 << (size * 8 - 1); + if (((add_number & mask) != 0 + || (fixP->fx_signed + && (add_number & hibit) != 0)) + && ((add_number & mask) != mask + || (add_number & hibit) == 0)) { char buf[50], buf2[50]; sprint_value (buf, fragP->fr_address + where); @@ -2498,6 +2688,13 @@ number_to_chars_littleendian (buf, val, n) } } +void +write_print_statistics (file) + FILE *file; +{ + fprintf (stderr, "fixups: %d\n", n_fixups); +} + /* for debugging */ extern int indent_level; extern void print_symbol_value_1 ();